Merge lp:~zulcss/ubuntu/precise/python-keystoneclient/new into lp:~ubuntu-cloud-archive/ubuntu/precise/python-keystoneclient/trunk

Proposed by Chuck Short
Status: Merged
Merged at revision: 26
Proposed branch: lp:~zulcss/ubuntu/precise/python-keystoneclient/new
Merge into: lp:~ubuntu-cloud-archive/ubuntu/precise/python-keystoneclient/trunk
Diff against target: 11180 lines (+8589/-754)
109 files modified
.gitignore (+2/-0)
AUTHORS (+11/-0)
PKG-INFO (+93/-64)
README.rst (+90/-62)
babel.cfg (+1/-0)
debian/changelog (+23/-0)
debian/control (+3/-3)
doc/source/_theme/layout.html (+83/-0)
doc/source/_theme/theme.conf (+4/-0)
doc/source/conf.py (+22/-11)
doc/source/index.rst (+11/-10)
doc/source/ref/client.rst (+0/-8)
doc/source/ref/endpoints.rst (+0/-11)
doc/source/ref/exceptions.rst (+0/-8)
doc/source/ref/generic-client.rst (+0/-12)
doc/source/ref/index.rst (+0/-16)
doc/source/ref/roles.rst (+0/-9)
doc/source/ref/services.rst (+0/-11)
doc/source/ref/tenants.rst (+0/-11)
doc/source/ref/users.rst (+0/-9)
doc/source/releases.rst (+28/-101)
doc/source/shell.rst (+34/-13)
doc/source/static/basic.css (+416/-0)
doc/source/static/default.css (+230/-0)
doc/source/static/jquery.tweet.js (+154/-0)
doc/source/static/nature.css (+245/-0)
doc/source/static/tweaks.css (+94/-0)
doc/source/using-api.rst (+19/-15)
examples/pki/certs/cacert.pem (+18/-0)
examples/pki/certs/middleware.pem (+33/-0)
examples/pki/certs/signing_cert.pem (+17/-0)
examples/pki/certs/ssl_cert.pem (+17/-0)
examples/pki/cms/auth_token_revoked.json (+1/-0)
examples/pki/cms/auth_token_revoked.pem (+42/-0)
examples/pki/cms/auth_token_scoped.json (+1/-0)
examples/pki/cms/auth_token_scoped.pem (+41/-0)
examples/pki/cms/auth_token_unscoped.json (+1/-0)
examples/pki/cms/auth_token_unscoped.pem (+17/-0)
examples/pki/cms/revocation_list.json (+1/-0)
examples/pki/cms/revocation_list.pem (+12/-0)
examples/pki/gen_pki.sh (+222/-0)
examples/pki/private/cakey.pem (+16/-0)
examples/pki/private/signing_key.pem (+16/-0)
examples/pki/private/ssl_key.pem (+16/-0)
keystoneclient/access.py (+144/-0)
keystoneclient/base.py (+126/-4)
keystoneclient/client.py (+72/-41)
keystoneclient/common/cms.py (+169/-0)
keystoneclient/contrib/bootstrap/shell.py (+28/-0)
keystoneclient/exceptions.py (+19/-1)
keystoneclient/generic/shell.py (+9/-7)
keystoneclient/locale/keystoneclient.pot (+20/-0)
keystoneclient/middleware/auth_token.py (+864/-0)
keystoneclient/middleware/test.py (+67/-0)
keystoneclient/openstack/common/cfg.py (+1653/-0)
keystoneclient/openstack/common/iniparser.py (+130/-0)
keystoneclient/openstack/common/jsonutils.py (+148/-0)
keystoneclient/openstack/common/setup.py (+63/-39)
keystoneclient/openstack/common/timeutils.py (+137/-0)
keystoneclient/service_catalog.py (+17/-3)
keystoneclient/shell.py (+97/-75)
keystoneclient/utils.py (+25/-4)
keystoneclient/v2_0/client.py (+135/-37)
keystoneclient/v2_0/shell.py (+28/-7)
keystoneclient/v2_0/tenants.py (+15/-3)
keystoneclient/v2_0/tokens.py (+9/-1)
keystoneclient/v3/__init__.py (+1/-0)
keystoneclient/v3/client.py (+85/-0)
keystoneclient/v3/credentials.py (+57/-0)
keystoneclient/v3/domains.py (+55/-0)
keystoneclient/v3/endpoints.py (+86/-0)
keystoneclient/v3/policies.py (+77/-0)
keystoneclient/v3/projects.py (+82/-0)
keystoneclient/v3/roles.py (+110/-0)
keystoneclient/v3/services.py (+60/-0)
keystoneclient/v3/users.py (+70/-0)
keystoneclient/versioninfo (+1/-1)
openstack-common.conf (+1/-1)
python_keystoneclient.egg-info/PKG-INFO (+93/-64)
python_keystoneclient.egg-info/SOURCES.txt (+66/-9)
python_keystoneclient.egg-info/requires.txt (+1/-1)
run_tests.sh (+6/-1)
setup.cfg (+14/-0)
setup.py (+2/-1)
tests/client_fixtures.py (+72/-0)
tests/test_access.py (+56/-0)
tests/test_auth_token_middleware.py (+670/-0)
tests/test_client.py (+37/-0)
tests/test_http.py (+31/-19)
tests/test_https.py (+10/-16)
tests/v2_0/test_auth.py (+0/-6)
tests/v2_0/test_ec2.py (+1/-1)
tests/v2_0/test_endpoints.py (+1/-1)
tests/v2_0/test_roles.py (+15/-17)
tests/v2_0/test_tenants.py (+55/-17)
tests/v2_0/test_tokens.py (+1/-1)
tests/v2_0/test_users.py (+1/-1)
tests/v3/test_credentials.py (+22/-0)
tests/v3/test_domains.py (+20/-0)
tests/v3/test_endpoints.py (+78/-0)
tests/v3/test_policies.py (+21/-0)
tests/v3/test_projects.py (+69/-0)
tests/v3/test_roles.py (+252/-0)
tests/v3/test_services.py (+21/-0)
tests/v3/test_users.py (+23/-0)
tests/v3/utils.py (+227/-0)
tools/install_venv.py (+25/-0)
tools/pip-requires (+1/-1)
tools/test-requires (+4/-0)
To merge this branch: bzr merge lp:~zulcss/ubuntu/precise/python-keystoneclient/new
Reviewer Review Type Date Requested Status
James Page Approve
Review via email: mp+137202@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

LGTM; please upload with -v to ensure change history maintained.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.gitignore'
--- .gitignore 2012-08-16 12:34:22 +0000
+++ .gitignore 2012-11-30 14:11:19 +0000
@@ -6,8 +6,10 @@
6.idea6.idea
7*.swp7*.swp
8*~8*~
9.tox
9AUTHORS10AUTHORS
10build11build
11dist12dist
12python_keystoneclient.egg-info13python_keystoneclient.egg-info
13keystoneclient/versioninfo14keystoneclient/versioninfo
15doc/source/api
1416
=== modified file 'AUTHORS'
--- AUTHORS 2012-09-07 13:13:18 +0000
+++ AUTHORS 2012-11-30 14:11:19 +0000
@@ -1,5 +1,7 @@
1Adam Gandelman <adamg@canonical.com>1Adam Gandelman <adamg@canonical.com>
2Adam Young <ayoung@redhat.com>
2Alan Pevec <apevec@redhat.com>3Alan Pevec <apevec@redhat.com>
4Alex Meade <alex.meade@rackspace.com>
3Anthony Young <sleepsonthefloor@gmail.com>5Anthony Young <sleepsonthefloor@gmail.com>
4Bhuvan Arumugam <bhuvan@apache.org>6Bhuvan Arumugam <bhuvan@apache.org>
5Brian Waldon <bcwaldon@gmail.com>7Brian Waldon <bcwaldon@gmail.com>
@@ -8,20 +10,29 @@
8Dean Troyer <dtroyer@gmail.com>10Dean Troyer <dtroyer@gmail.com>
9Dolph Mathews <dolph.mathews@gmail.com>11Dolph Mathews <dolph.mathews@gmail.com>
10Dominik Heidler <dheidler@suse.de>12Dominik Heidler <dheidler@suse.de>
13Doug Hellmann <doug.hellmann@dreamhost.com>
11Everett Toews <everett.toews@gmail.com>14Everett Toews <everett.toews@gmail.com>
12Gabriel Hurley <gabriel@strikeawe.com>15Gabriel Hurley <gabriel@strikeawe.com>
13Ghe Rivero <ghe@debian.org>16Ghe Rivero <ghe@debian.org>
14Hengqing Hu <hudayou@hotmail.com>17Hengqing Hu <hudayou@hotmail.com>
18Henry Nash <henryn@linux.vnet.ibm.com>
19Ionuț Arțăriși <iartarisi@suse.cz>
15jakedahn <jake@ansolabs.com>20jakedahn <jake@ansolabs.com>
21Jay Pipes <jaypipes@gmail.com>
16Jesse Andrews <anotherjesse@gmail.com>22Jesse Andrews <anotherjesse@gmail.com>
23Joe Gordon <jogo@cloudscaling.com>
17Joe Heck <heckj@mac.com>24Joe Heck <heckj@mac.com>
25Joseph W. Breu <breu@breu.org>
18Josh Kearney <josh@jk0.org>26Josh Kearney <josh@jk0.org>
19Ken Thomas <krt@yahoo-inc.com>27Ken Thomas <krt@yahoo-inc.com>
28Kevin L. Mitchell <kevin.mitchell@rackspace.com>
29Laurence Miao <laurence.miao@gmail.com>
20Liem Nguyen <liem.m.nguyen@gmail.com>30Liem Nguyen <liem.m.nguyen@gmail.com>
21Lorin Hochstein <lorin@nimbisservices.com>31Lorin Hochstein <lorin@nimbisservices.com>
22lrqrun <lrqrun@gmail.com>32lrqrun <lrqrun@gmail.com>
23Monty Taylor <mordred@inaugust.com>33Monty Taylor <mordred@inaugust.com>
24Peng Yong <ppyy@pubyun.com>34Peng Yong <ppyy@pubyun.com>
35Sam Morrison <sorrison@gmail.com>
25Sascha Peilicke <saschpe@suse.de>36Sascha Peilicke <saschpe@suse.de>
26termie <github@anarkystic.com>37termie <github@anarkystic.com>
27Thierry Carrez <thierry@openstack.org>38Thierry Carrez <thierry@openstack.org>
2839
=== modified file 'PKG-INFO'
--- PKG-INFO 2012-09-07 13:13:18 +0000
+++ PKG-INFO 2012-11-30 14:11:19 +0000
@@ -1,28 +1,27 @@
1Metadata-Version: 1.11Metadata-Version: 1.1
2Name: python-keystoneclient2Name: python-keystoneclient
3Version: 0.1.33Version: 0.2.0
4Summary: Client library for OpenStack Keystone API4Summary: Client library for OpenStack Identity API (Keystone)
5Home-page: https://github.com/openstack/python-keystoneclient5Home-page: https://github.com/openstack/python-keystoneclient
6Author: Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss6Author: Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss
7Author-email: gabriel.hurley@nebula.com7Author-email: gabriel.hurley@nebula.com
8License: Apache8License: Apache
9Description: Python bindings to the OpenStack Keystone API9Description: Python bindings to the OpenStack Identity API (Keystone)
10 =============================================10 ========================================================
11 11
12 This is a client for the OpenStack Keystone API. There's a Python API (the12 This is a client for the OpenStack Identity API, implemented by Keystone.
13 ``keystoneclient`` module), and a command-line script (``keystone``). The13 There's a Python API (the ``keystoneclient`` module), and a command-line script
14 Keystone 2.0 API is still a moving target, so this module will remain in14 (``keystone``).
15 "Beta" status until the API is finalized and fully implemented.15
16 16 Development takes place via the usual OpenStack processes as outlined in the
17 Development takes place via the usual OpenStack processes as outlined in17 `OpenStack wiki`_. The master repository is on GitHub__.
18 the `OpenStack wiki`_. The master repository is on GitHub__.
19 18
20 __ http://wiki.openstack.org/HowToContribute19 __ http://wiki.openstack.org/HowToContribute
21 __ http://github.com/openstack/python-keystoneclient20 __ http://github.com/openstack/python-keystoneclient
22 21
23 This code a fork of `Rackspace's python-novaclient`__ which is in turn a fork of22 This code a fork of `Rackspace's python-novaclient`__ which is in turn a fork
24 `Jacobian's python-cloudservers`__. The python-keystoneclient is licensed under23 of `Jacobian's python-cloudservers`__. The python-keystoneclient is licensed
25 the Apache License like the rest of OpenStack.24 under the Apache License like the rest of OpenStack.
26 25
27 __ http://github.com/rackspace/python-novaclient26 __ http://github.com/rackspace/python-novaclient
28 __ http://github.com/jacobian/python-cloudservers27 __ http://github.com/jacobian/python-cloudservers
@@ -35,7 +34,7 @@
35 34
36 By way of a quick-start::35 By way of a quick-start::
37 36
38 # use v2.0 auth with http://example.com:5000/v2.0")37 # use v2.0 auth with http://example.com:5000/v2.0
39 >>> from keystoneclient.v2_0 import client38 >>> from keystoneclient.v2_0 import client
40 >>> keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)39 >>> keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)
41 >>> keystone.tenants.list()40 >>> keystone.tenants.list()
@@ -46,40 +45,45 @@
46 Command-line API45 Command-line API
47 ----------------46 ----------------
48 47
49 Installing this package gets you a shell command, ``keystone``, that you48 Installing this package gets you a shell command, ``keystone``, that you can
50 can use to interact with Keystone's Identity API.49 use to interact with OpenStack's Identity API.
51 50
52 You'll need to provide your OpenStack tenant, username and password. You can51 You'll need to provide your OpenStack tenant, username and password. You can do
53 do this with the ``--os-tenant-name``, ``--os-username`` and ``--os-password``52 this with the ``--os-tenant-name``, ``--os-username`` and ``--os-password``
54 params, but it's easier to just set them as environment variables::53 params, but it's easier to just set them as environment variables::
55 54
56 export OS_TENANT_NAME=project55 export OS_TENANT_NAME=project
57 export OS_USERNAME=user56 export OS_USERNAME=user
58 export OS_PASSWORD=pass57 export OS_PASSWORD=pass
59 58
60 You will also need to define the authentication url with ``--os-auth-url`` and the59 You will also need to define the authentication url with ``--os-auth-url`` and
61 version of the API with ``--os-identity-api-version``. Or set them as an environment60 the version of the API with ``--os-identity-api-version``. Or set them as an
62 variables as well::61 environment variables as well::
63 62
64 export OS_AUTH_URL=http://example.com:5000/v2.063 export OS_AUTH_URL=http://example.com:5000/v2.0
65 export OS_IDENTITY_API_VERSION=2.064 export OS_IDENTITY_API_VERSION=2.0
66 65
67 Alternatively, to authenticate to Keystone without a username/password,66 Alternatively, to bypass username/password authentication, you can provide a
68 such as when there are no users in the database yet, use the service67 pre-established token. In Keystone, this approach is necessary to bootstrap the
69 token and endpoint arguemnts. The service token is set in keystone.conf as68 service with an administrative user, tenant & role (to do so, provide the
70 ``admin_token``; set it with ``service_token``. Note: keep the service token69 client with the value of your ``admin_token`` defined in ``keystone.conf`` in
71 secret as it allows total access to Keystone's database. The admin endpoint is set70 addition to the URL of your admin API deployment, typically on port 35357)::
72 with ``--endpoint`` or ``SERVICE_ENDPOINT``::71
73 72 export OS_SERVICE_TOKEN=thequickbrownfox-jumpsover-thelazydog
74 export SERVICE_TOKEN=thequickbrownfox-jumpsover-thelazydog73 export OS_SERVICE_ENDPOINT=http://example.com:35357/v2.0
75 export SERVICE_ENDPOINT=http://example.com:35357/v2.074
76 75 Since the Identity service can return multiple regions in the service catalog,
77 Since Keystone can return multiple regions in the Service Catalog, you76 you can specify the one you want with ``--os-region-name`` (or ``export
78 can specify the one you want with ``--region_name`` (or77 OS_REGION_NAME``)::
79 ``export OS_REGION_NAME``). It defaults to the first in the list returned.78
80 79 export OS_REGION_NAME=north
81 You'll find complete documentation on the shell by running80
82 ``keystone help``::81 .. WARNING::
82
83 If a region is not specified and multiple regions are returned by the
84 Identity service, the client may not access the same region consistently.
85
86 You'll find complete documentation on the shell by running ``keystone help``::
83 87
84 usage: keystone [--os-username <auth-user-name>]88 usage: keystone [--os-username <auth-user-name>]
85 [--os-password <auth-password>]89 [--os-password <auth-password>]
@@ -87,14 +91,17 @@
87 [--os-tenant-id <tenant-id>] [--os-auth-url <auth-url>]91 [--os-tenant-id <tenant-id>] [--os-auth-url <auth-url>]
88 [--os-region-name <region-name>]92 [--os-region-name <region-name>]
89 [--os-identity-api-version <identity-api-version>]93 [--os-identity-api-version <identity-api-version>]
90 [--token <service-token>] [--endpoint <service-endpoint>]94 [--os-token <service-token>]
95 [--os-endpoint <service-endpoint>]
96 [--os-cacert <ca-certificate>] [--os-cert <certificate>]
97 [--os-key <key>] [--insecure]
91 <subcommand> ...98 <subcommand> ...
92 99
93 Command-line interface to the OpenStack Identity API.100 Command-line interface to the OpenStack Identity API.
94 101
95 Positional arguments:102 Positional arguments:
96 <subcommand>103 <subcommand>
97 catalog List service catalog, possibly filtered by service.104 catalog
98 ec2-credentials-create105 ec2-credentials-create
99 Create EC2-compatibile credentials for user per tenant106 Create EC2-compatibile credentials for user per tenant
100 ec2-credentials-delete107 ec2-credentials-delete
@@ -105,13 +112,12 @@
105 List EC2-compatibile credentials for a user112 List EC2-compatibile credentials for a user
106 endpoint-create Create a new endpoint associated with a service113 endpoint-create Create a new endpoint associated with a service
107 endpoint-delete Delete a service endpoint114 endpoint-delete Delete a service endpoint
108 endpoint-get Find endpoint filtered by a specific attribute or115 endpoint-get
109 service type
110 endpoint-list List configured service endpoints116 endpoint-list List configured service endpoints
111 role-create Create new role117 role-create Create new role
112 role-delete Delete role118 role-delete Delete role
113 role-get Display role details119 role-get Display role details
114 role-list List all available roles120 role-list List all roles
115 service-create Add service to Service Catalog121 service-create Add service to Service Catalog
116 service-delete Delete service from Service Catalog122 service-delete Delete service from Service Catalog
117 service-get Display service from Service Catalog123 service-get Display service from Service Catalog
@@ -121,46 +127,69 @@
121 tenant-get Display tenant details127 tenant-get Display tenant details
122 tenant-list List all tenants128 tenant-list List all tenants
123 tenant-update Update tenant name, description, enabled status129 tenant-update Update tenant name, description, enabled status
124 token-get Display the current user token130 token-get
125 user-create Create new user131 user-create Create new user
126 user-delete Delete user132 user-delete Delete user
133 user-get Display user details.
127 user-list List users134 user-list List users
128 user-password-update135 user-password-update
129 Update user password136 Update user password
130 user-role-add Add role to user137 user-role-add Add role to user
138 user-role-list List roles granted to a user
131 user-role-remove Remove role from user139 user-role-remove Remove role from user
132 user-role-list List roles for user
133 user-update Update user's name, email, and enabled status140 user-update Update user's name, email, and enabled status
134 discover Discover Keystone servers and show authentication141 discover Discover Keystone servers and show authentication
135 protocols and142 protocols and
143 bootstrap Grants a new role to a new user on a new tenant, after
144 creating each.
145 bash-completion Prints all of the commands and options to stdout.
136 help Display help about this program or one of its146 help Display help about this program or one of its
137 subcommands.147 subcommands.
138 148
139 Optional arguments:149 Optional arguments:
140 --os-username <auth-user-name>150 --os-username <auth-user-name>
141 Defaults to env[OS_USERNAME]151 Name used for authentication with the OpenStack
142 --os-password <auth-password>152 Identity service. Defaults to env[OS_USERNAME]
143 Defaults to env[OS_PASSWORD]153 --os-password <auth-password>
144 --os-tenant-name <auth-tenant-name>154 Password used for authentication with the OpenStack
145 Defaults to env[OS_TENANT_NAME]155 Identity service. Defaults to env[OS_PASSWORD]
146 --os-tenant-id <tenant-id>156 --os-tenant-name <auth-tenant-name>
147 Defaults to env[OS_TENANT_ID]157 Tenant to request authorization on. Defaults to
148 --os-auth-url <auth-url>158 env[OS_TENANT_NAME]
149 Defaults to env[OS_AUTH_URL]159 --os-tenant-id <tenant-id>
150 --os-region-name <region-name>160 Tenant to request authorization on. Defaults to
161 env[OS_TENANT_ID]
162 --os-auth-url <auth-url>
163 Specify the Identity endpoint to use for
164 authentication. Defaults to env[OS_AUTH_URL]
165 --os-region-name <region-name>
151 Defaults to env[OS_REGION_NAME]166 Defaults to env[OS_REGION_NAME]
152 --os-identity-api-version <identity-api-version>167 --os-identity-api-version <identity-api-version>
153 Defaults to env[OS_IDENTITY_API_VERSION] or 2.0168 Defaults to env[OS_IDENTITY_API_VERSION] or 2.0
154 --token <service-token>169 --os-token <service-token>
155 Defaults to env[SERVICE_TOKEN]170 Specify an existing token to use instead of retrieving
156 --endpoint <service-endpoint>171 one via authentication (e.g. with username &
157 Defaults to env[SERVICE_ENDPOINT]172 password). Defaults to env[OS_SERVICE_TOKEN]
173 --os-endpoint <service-endpoint>
174 Specify an endpoint to use instead of retrieving one
175 from the service catalog (via authentication).
176 Defaults to env[OS_SERVICE_ENDPOINT]
177 --os-cacert <ca-certificate>
178 Defaults to env[OS_CACERT]
179 --os-cert <certificate>
180 Defaults to env[OS_CERT]
181 --os-key <key> Defaults to env[OS_KEY]
182 --insecure Explicitly allow keystoneclient to perform "insecure"
183 SSL (https) requests. The server's certificate will
184 not be verified against any certificate authorities.
185 This option should be used with caution.
158 186
159 See "keystone help COMMAND" for help on a specific command.187 See "keystone help COMMAND" for help on a specific command.
160 188
161Platform: UNKNOWN189Platform: UNKNOWN
162Classifier: Development Status :: 4 - Beta190Classifier: Development Status :: 4 - Beta
163Classifier: Environment :: Console191Classifier: Environment :: Console
192Classifier: Environment :: OpenStack
164Classifier: Intended Audience :: Developers193Classifier: Intended Audience :: Developers
165Classifier: Intended Audience :: Information Technology194Classifier: Intended Audience :: Information Technology
166Classifier: License :: OSI Approved :: Apache Software License195Classifier: License :: OSI Approved :: Apache Software License
167196
=== modified file 'README.rst'
--- README.rst 2012-08-16 12:34:22 +0000
+++ README.rst 2012-11-30 14:11:19 +0000
@@ -1,20 +1,19 @@
1Python bindings to the OpenStack Keystone API1Python bindings to the OpenStack Identity API (Keystone)
2=============================================2========================================================
33
4This is a client for the OpenStack Keystone API. There's a Python API (the4This is a client for the OpenStack Identity API, implemented by Keystone.
5``keystoneclient`` module), and a command-line script (``keystone``). The5There's a Python API (the ``keystoneclient`` module), and a command-line script
6Keystone 2.0 API is still a moving target, so this module will remain in6(``keystone``).
7"Beta" status until the API is finalized and fully implemented.7
88Development takes place via the usual OpenStack processes as outlined in the
9Development takes place via the usual OpenStack processes as outlined in9`OpenStack wiki`_. The master repository is on GitHub__.
10the `OpenStack wiki`_. The master repository is on GitHub__.
1110
12__ http://wiki.openstack.org/HowToContribute11__ http://wiki.openstack.org/HowToContribute
13__ http://github.com/openstack/python-keystoneclient12__ http://github.com/openstack/python-keystoneclient
1413
15This code a fork of `Rackspace's python-novaclient`__ which is in turn a fork of14This code a fork of `Rackspace's python-novaclient`__ which is in turn a fork
16`Jacobian's python-cloudservers`__. The python-keystoneclient is licensed under15of `Jacobian's python-cloudservers`__. The python-keystoneclient is licensed
17the Apache License like the rest of OpenStack.16under the Apache License like the rest of OpenStack.
1817
19__ http://github.com/rackspace/python-novaclient18__ http://github.com/rackspace/python-novaclient
20__ http://github.com/jacobian/python-cloudservers19__ http://github.com/jacobian/python-cloudservers
@@ -27,7 +26,7 @@
2726
28By way of a quick-start::27By way of a quick-start::
2928
30 # use v2.0 auth with http://example.com:5000/v2.0")29 # use v2.0 auth with http://example.com:5000/v2.0
31 >>> from keystoneclient.v2_0 import client30 >>> from keystoneclient.v2_0 import client
32 >>> keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)31 >>> keystone = client.Client(username=USERNAME, password=PASSWORD, tenant_name=TENANT, auth_url=AUTH_URL)
33 >>> keystone.tenants.list()32 >>> keystone.tenants.list()
@@ -38,40 +37,45 @@
38Command-line API37Command-line API
39----------------38----------------
4039
41Installing this package gets you a shell command, ``keystone``, that you40Installing this package gets you a shell command, ``keystone``, that you can
42can use to interact with Keystone's Identity API.41use to interact with OpenStack's Identity API.
4342
44You'll need to provide your OpenStack tenant, username and password. You can43You'll need to provide your OpenStack tenant, username and password. You can do
45do this with the ``--os-tenant-name``, ``--os-username`` and ``--os-password``44this with the ``--os-tenant-name``, ``--os-username`` and ``--os-password``
46params, but it's easier to just set them as environment variables::45params, but it's easier to just set them as environment variables::
4746
48 export OS_TENANT_NAME=project47 export OS_TENANT_NAME=project
49 export OS_USERNAME=user48 export OS_USERNAME=user
50 export OS_PASSWORD=pass49 export OS_PASSWORD=pass
5150
52You will also need to define the authentication url with ``--os-auth-url`` and the51You will also need to define the authentication url with ``--os-auth-url`` and
53version of the API with ``--os-identity-api-version``. Or set them as an environment52the version of the API with ``--os-identity-api-version``. Or set them as an
54variables as well::53environment variables as well::
5554
56 export OS_AUTH_URL=http://example.com:5000/v2.055 export OS_AUTH_URL=http://example.com:5000/v2.0
57 export OS_IDENTITY_API_VERSION=2.056 export OS_IDENTITY_API_VERSION=2.0
5857
59Alternatively, to authenticate to Keystone without a username/password,58Alternatively, to bypass username/password authentication, you can provide a
60such as when there are no users in the database yet, use the service59pre-established token. In Keystone, this approach is necessary to bootstrap the
61token and endpoint arguemnts. The service token is set in keystone.conf as60service with an administrative user, tenant & role (to do so, provide the
62``admin_token``; set it with ``service_token``. Note: keep the service token61client with the value of your ``admin_token`` defined in ``keystone.conf`` in
63secret as it allows total access to Keystone's database. The admin endpoint is set62addition to the URL of your admin API deployment, typically on port 35357)::
64with ``--endpoint`` or ``SERVICE_ENDPOINT``::63
6564 export OS_SERVICE_TOKEN=thequickbrownfox-jumpsover-thelazydog
66 export SERVICE_TOKEN=thequickbrownfox-jumpsover-thelazydog65 export OS_SERVICE_ENDPOINT=http://example.com:35357/v2.0
67 export SERVICE_ENDPOINT=http://example.com:35357/v2.066
6867Since the Identity service can return multiple regions in the service catalog,
69Since Keystone can return multiple regions in the Service Catalog, you68you can specify the one you want with ``--os-region-name`` (or ``export
70can specify the one you want with ``--region_name`` (or69OS_REGION_NAME``)::
71``export OS_REGION_NAME``). It defaults to the first in the list returned.70
7271 export OS_REGION_NAME=north
73You'll find complete documentation on the shell by running72
74``keystone help``::73.. WARNING::
74
75 If a region is not specified and multiple regions are returned by the
76 Identity service, the client may not access the same region consistently.
77
78You'll find complete documentation on the shell by running ``keystone help``::
7579
76 usage: keystone [--os-username <auth-user-name>]80 usage: keystone [--os-username <auth-user-name>]
77 [--os-password <auth-password>]81 [--os-password <auth-password>]
@@ -79,14 +83,17 @@
79 [--os-tenant-id <tenant-id>] [--os-auth-url <auth-url>]83 [--os-tenant-id <tenant-id>] [--os-auth-url <auth-url>]
80 [--os-region-name <region-name>]84 [--os-region-name <region-name>]
81 [--os-identity-api-version <identity-api-version>]85 [--os-identity-api-version <identity-api-version>]
82 [--token <service-token>] [--endpoint <service-endpoint>]86 [--os-token <service-token>]
87 [--os-endpoint <service-endpoint>]
88 [--os-cacert <ca-certificate>] [--os-cert <certificate>]
89 [--os-key <key>] [--insecure]
83 <subcommand> ...90 <subcommand> ...
8491
85 Command-line interface to the OpenStack Identity API.92 Command-line interface to the OpenStack Identity API.
8693
87 Positional arguments:94 Positional arguments:
88 <subcommand>95 <subcommand>
89 catalog List service catalog, possibly filtered by service.96 catalog
90 ec2-credentials-create97 ec2-credentials-create
91 Create EC2-compatibile credentials for user per tenant98 Create EC2-compatibile credentials for user per tenant
92 ec2-credentials-delete99 ec2-credentials-delete
@@ -97,13 +104,12 @@
97 List EC2-compatibile credentials for a user104 List EC2-compatibile credentials for a user
98 endpoint-create Create a new endpoint associated with a service105 endpoint-create Create a new endpoint associated with a service
99 endpoint-delete Delete a service endpoint106 endpoint-delete Delete a service endpoint
100 endpoint-get Find endpoint filtered by a specific attribute or107 endpoint-get
101 service type
102 endpoint-list List configured service endpoints108 endpoint-list List configured service endpoints
103 role-create Create new role109 role-create Create new role
104 role-delete Delete role110 role-delete Delete role
105 role-get Display role details111 role-get Display role details
106 role-list List all available roles112 role-list List all roles
107 service-create Add service to Service Catalog113 service-create Add service to Service Catalog
108 service-delete Delete service from Service Catalog114 service-delete Delete service from Service Catalog
109 service-get Display service from Service Catalog115 service-get Display service from Service Catalog
@@ -113,39 +119,61 @@
113 tenant-get Display tenant details119 tenant-get Display tenant details
114 tenant-list List all tenants120 tenant-list List all tenants
115 tenant-update Update tenant name, description, enabled status121 tenant-update Update tenant name, description, enabled status
116 token-get Display the current user token122 token-get
117 user-create Create new user123 user-create Create new user
118 user-delete Delete user124 user-delete Delete user
125 user-get Display user details.
119 user-list List users126 user-list List users
120 user-password-update127 user-password-update
121 Update user password128 Update user password
122 user-role-add Add role to user129 user-role-add Add role to user
130 user-role-list List roles granted to a user
123 user-role-remove Remove role from user131 user-role-remove Remove role from user
124 user-role-list List roles for user
125 user-update Update user's name, email, and enabled status132 user-update Update user's name, email, and enabled status
126 discover Discover Keystone servers and show authentication133 discover Discover Keystone servers and show authentication
127 protocols and134 protocols and
135 bootstrap Grants a new role to a new user on a new tenant, after
136 creating each.
137 bash-completion Prints all of the commands and options to stdout.
128 help Display help about this program or one of its138 help Display help about this program or one of its
129 subcommands.139 subcommands.
130140
131 Optional arguments:141 Optional arguments:
132 --os-username <auth-user-name>142 --os-username <auth-user-name>
133 Defaults to env[OS_USERNAME]143 Name used for authentication with the OpenStack
134 --os-password <auth-password>144 Identity service. Defaults to env[OS_USERNAME]
135 Defaults to env[OS_PASSWORD]145 --os-password <auth-password>
136 --os-tenant-name <auth-tenant-name>146 Password used for authentication with the OpenStack
137 Defaults to env[OS_TENANT_NAME]147 Identity service. Defaults to env[OS_PASSWORD]
138 --os-tenant-id <tenant-id>148 --os-tenant-name <auth-tenant-name>
139 Defaults to env[OS_TENANT_ID]149 Tenant to request authorization on. Defaults to
140 --os-auth-url <auth-url>150 env[OS_TENANT_NAME]
141 Defaults to env[OS_AUTH_URL]151 --os-tenant-id <tenant-id>
142 --os-region-name <region-name>152 Tenant to request authorization on. Defaults to
153 env[OS_TENANT_ID]
154 --os-auth-url <auth-url>
155 Specify the Identity endpoint to use for
156 authentication. Defaults to env[OS_AUTH_URL]
157 --os-region-name <region-name>
143 Defaults to env[OS_REGION_NAME]158 Defaults to env[OS_REGION_NAME]
144 --os-identity-api-version <identity-api-version>159 --os-identity-api-version <identity-api-version>
145 Defaults to env[OS_IDENTITY_API_VERSION] or 2.0160 Defaults to env[OS_IDENTITY_API_VERSION] or 2.0
146 --token <service-token>161 --os-token <service-token>
147 Defaults to env[SERVICE_TOKEN]162 Specify an existing token to use instead of retrieving
148 --endpoint <service-endpoint>163 one via authentication (e.g. with username &
149 Defaults to env[SERVICE_ENDPOINT]164 password). Defaults to env[OS_SERVICE_TOKEN]
165 --os-endpoint <service-endpoint>
166 Specify an endpoint to use instead of retrieving one
167 from the service catalog (via authentication).
168 Defaults to env[OS_SERVICE_ENDPOINT]
169 --os-cacert <ca-certificate>
170 Defaults to env[OS_CACERT]
171 --os-cert <certificate>
172 Defaults to env[OS_CERT]
173 --os-key <key> Defaults to env[OS_KEY]
174 --insecure Explicitly allow keystoneclient to perform "insecure"
175 SSL (https) requests. The server's certificate will
176 not be verified against any certificate authorities.
177 This option should be used with caution.
150178
151See "keystone help COMMAND" for help on a specific command.179 See "keystone help COMMAND" for help on a specific command.
152180
=== added file 'babel.cfg'
--- babel.cfg 1970-01-01 00:00:00 +0000
+++ babel.cfg 2012-11-30 14:11:19 +0000
@@ -0,0 +1,1 @@
1[python: **.py]
02
=== modified file 'debian/changelog'
--- debian/changelog 2012-10-10 18:40:31 +0000
+++ debian/changelog 2012-11-30 14:11:19 +0000
@@ -1,3 +1,26 @@
1python-keystoneclient (1:0.2.0-0ubuntu1~cloud0) precise-grizzly; urgency=low
2
3 * New upstream release for the Ubuntu Cloud Archive.
4
5 -- Chuck Short <zulcss@ubuntu.com> Fri, 30 Nov 2012 08:07:06 -0600
6
7python-keystoneclient (1:0.2.0-0ubuntu1) raring; urgency=low
8
9 * New upstream release.
10 * debian/control: Add python-pkg-resources. (LP: #1071032)
11
12 -- Chuck Short <zulcss@ubuntu.com> Thu, 29 Nov 2012 12:46:21 -0600
13
14python-keystoneclient (1:0.1.3.37-0ubuntu1) raring-proposed; urgency=low
15
16 [ Adam Gandelman ]
17 * New upstream release.
18
19 [ Adrien Cunin ]
20 * Typo and cosmetic fixes to package description (LP: #960350)
21
22 -- Adam Gandelman <adamg@canonical.com> Wed, 31 Oct 2012 09:17:26 +0100
23
1python-keystoneclient (1:0.1.3-0ubuntu1~cloud0) precise-folsom; urgency=low24python-keystoneclient (1:0.1.3-0ubuntu1~cloud0) precise-folsom; urgency=low
225
3 * New upstream snapshot for the Ubuntu Cloud Archive. 26 * New upstream snapshot for the Ubuntu Cloud Archive.
427
=== modified file 'debian/control'
--- debian/control 2012-03-02 10:31:44 +0000
+++ debian/control 2012-11-30 14:11:19 +0000
@@ -8,7 +8,7 @@
88
9Package: python-keystoneclient9Package: python-keystoneclient
10Architecture: all10Architecture: all
11Depends: ${python:Depends}, ${misc:Depends}, python-httplib211Depends: ${python:Depends}, ${misc:Depends}, python-pkg-resources
12Description: Client libary for Openstack Keystone API12Description: Client library for OpenStack Identity API
13 This is a client for the OpenStack Keystone API. There's a Python API 13 This is a client for the OpenStack Identity API. There's a Python API
14 (the ``keystoneclient`` module), and a command-line script (``keystone``).14 (the ``keystoneclient`` module), and a command-line script (``keystone``).
1515
=== added directory 'doc/source/_templates'
=== added file 'doc/source/_templates/.placeholder'
=== added directory 'doc/source/_theme'
=== added file 'doc/source/_theme/layout.html'
--- doc/source/_theme/layout.html 1970-01-01 00:00:00 +0000
+++ doc/source/_theme/layout.html 2012-11-30 14:11:19 +0000
@@ -0,0 +1,83 @@
1{% extends "basic/layout.html" %}
2{% set css_files = css_files + ['_static/tweaks.css'] %}
3{% set script_files = script_files + ['_static/jquery.tweet.js'] %}
4
5{%- macro sidebar() %}
6 {%- if not embedded %}{% if not theme_nosidebar|tobool %}
7 <div class="sphinxsidebar">
8 <div class="sphinxsidebarwrapper">
9 {%- block sidebarlogo %}
10 {%- if logo %}
11 <p class="logo"><a href="{{ pathto(master_doc) }}">
12 <img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
13 </a></p>
14 {%- endif %}
15 {%- endblock %}
16 {%- block sidebartoc %}
17 {%- if display_toc %}
18 <h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
19 {{ toc }}
20 {%- endif %}
21 {%- endblock %}
22 {%- block sidebarrel %}
23 {%- if prev %}
24 <h4>{{ _('Previous topic') }}</h4>
25 <p class="topless"><a href="{{ prev.link|e }}"
26 title="{{ _('previous chapter') }}">{{ prev.title }}</a></p>
27 {%- endif %}
28 {%- if next %}
29 <h4>{{ _('Next topic') }}</h4>
30 <p class="topless"><a href="{{ next.link|e }}"
31 title="{{ _('next chapter') }}">{{ next.title }}</a></p>
32 {%- endif %}
33 {%- endblock %}
34 {%- block sidebarsourcelink %}
35 {%- if show_source and has_source and sourcename %}
36 <h3>{{ _('This Page') }}</h3>
37 <ul class="this-page-menu">
38 <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
39 rel="nofollow">{{ _('Show Source') }}</a></li>
40 </ul>
41 {%- endif %}
42 {%- endblock %}
43 {%- if customsidebar %}
44 {% include customsidebar %}
45 {%- endif %}
46 {%- block sidebarsearch %}
47 {%- if pagename != "search" %}
48 <div id="searchbox" style="display: none">
49 <h3>{{ _('Quick search') }}</h3>
50 <form class="search" action="{{ pathto('search') }}" method="get">
51 <input type="text" name="q" size="18" />
52 <input type="submit" value="{{ _('Go') }}" />
53 <input type="hidden" name="check_keywords" value="yes" />
54 <input type="hidden" name="area" value="default" />
55 </form>
56 <p class="searchtip" style="font-size: 90%">
57 {{ _('Enter search terms or a module, class or function name.') }}
58 </p>
59 </div>
60 <script type="text/javascript">$('#searchbox').show(0);</script>
61 {%- endif %}
62 {%- endblock %}
63 </div>
64 </div>
65 {%- endif %}{% endif %}
66{%- endmacro %}
67
68{% block relbar1 %}{% endblock relbar1 %}
69
70{% block header %}
71 <div id="header">
72 <h1 id="logo"><a href="http://www.openstack.org/">OpenStack</a></h1>
73 <ul id="navigation">
74 <li><a href="http://www.openstack.org/" title="Go to the Home page" class="link">Home</a></li>
75 <li><a href="http://www.openstack.org/projects/" title="Go to the OpenStack Projects page">Projects</a></li>
76 <li><a href="http://www.openstack.org/user-stories/" title="Go to the User Stories page" class="link">User Stories</a></li>
77 <li><a href="http://www.openstack.org/community/" title="Go to the Community page" class="link">Community</a></li>
78 <li><a href="http://www.openstack.org/blog/" title="Go to the OpenStack Blog">Blog</a></li>
79 <li><a href="http://wiki.openstack.org/" title="Go to the OpenStack Wiki">Wiki</a></li>
80 <li><a href="http://docs.openstack.org/" title="Go to OpenStack Documentation" class="current">Documentation</a></li>
81 </ul>
82 </div>
83{% endblock %}
0\ No newline at end of file84\ No newline at end of file
185
=== added file 'doc/source/_theme/theme.conf'
--- doc/source/_theme/theme.conf 1970-01-01 00:00:00 +0000
+++ doc/source/_theme/theme.conf 2012-11-30 14:11:19 +0000
@@ -0,0 +1,4 @@
1[theme]
2inherit = basic
3stylesheet = nature.css
4pygments_style = tango
05
=== modified file 'doc/source/conf.py'
--- doc/source/conf.py 2012-09-07 13:13:18 +0000
+++ doc/source/conf.py 2012-11-30 14:11:19 +0000
@@ -16,7 +16,7 @@
16import sys16import sys
1717
18sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),18sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
19 "..", "..")))19 '..', '..')))
2020
21# If extensions (or modules to document with autodoc) are in another directory,21# If extensions (or modules to document with autodoc) are in another directory,
22# add these directories to sys.path here. If the directory is relative to the22# add these directories to sys.path here. If the directory is relative to the
@@ -28,7 +28,12 @@
28# Add any Sphinx extension module names here, as strings. They can be28# Add any Sphinx extension module names here, as strings. They can be
29# extensions29# extensions
30# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.30# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
31extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx']31extensions = ['sphinx.ext.autodoc',
32 'sphinx.ext.todo',
33 'sphinx.ext.coverage',
34 'sphinx.ext.intersphinx']
35
36todo_include_todos = True
3237
33# Add any paths that contain templates here, relative to this directory.38# Add any paths that contain templates here, relative to this directory.
34templates_path = ['_templates']39templates_path = ['_templates']
@@ -50,10 +55,10 @@
50# |version| and |release|, also used in various other places throughout the55# |version| and |release|, also used in various other places throughout the
51# built documents.56# built documents.
52#57#
53# The short X.Y version.58# The short XXXX.Y version.
54version = '2.7'59version = '2012.3'
55# The full version, including alpha/beta/rc tags.60# The full version, including alpha/beta/rc tags.
56release = '2.7.0'61release = '2012.3-dev'
5762
58# The language for content autogenerated by Sphinx. Refer to documentation63# The language for content autogenerated by Sphinx. Refer to documentation
59# for a list of supported languages.64# for a list of supported languages.
@@ -98,7 +103,8 @@
98103
99# The theme to use for HTML and HTML Help pages. Major themes that come with104# The theme to use for HTML and HTML Help pages. Major themes that come with
100# Sphinx are currently 'default' and 'sphinxdoc'.105# Sphinx are currently 'default' and 'sphinxdoc'.
101html_theme = 'nature'106html_theme_path = ["."]
107html_theme = '_theme'
102108
103# Theme options are theme-specific and customize the look and feel of a theme109# Theme options are theme-specific and customize the look and feel of a theme
104# further. For a list of options available for each theme, see the110# further. For a list of options available for each theme, see the
@@ -127,11 +133,12 @@
127# Add any paths that contain custom static files (such as style sheets) here,133# Add any paths that contain custom static files (such as style sheets) here,
128# relative to this directory. They are copied after the builtin static files,134# relative to this directory. They are copied after the builtin static files,
129# so a file named "default.css" will overwrite the builtin "default.css".135# so a file named "default.css" will overwrite the builtin "default.css".
130html_static_path = ['_static']136html_static_path = ['static']
131137
132# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,138# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
133# using the given strftime format.139# using the given strftime format.
134#html_last_updated_fmt = '%b %d, %Y'140git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1"
141html_last_updated_fmt = os.popen(git_cmd).read()
135142
136# If true, SmartyPants will be used to convert quotes and dashes to143# If true, SmartyPants will be used to convert quotes and dashes to
137# typographically correct entities.144# typographically correct entities.
@@ -181,8 +188,9 @@
181# .188# .
182latex_documents = [189latex_documents = [
183 ('index', 'python-keystoneclient.tex',190 ('index', 'python-keystoneclient.tex',
184 u'python-keystoneclient Documentation',191 u'python-keystoneclient Documentation',
185 u'Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss', 'manual'),192 u'Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss',
193 'manual'),
186]194]
187195
188# The name of an image file (relative to this directory) to place at the top of196# The name of an image file (relative to this directory) to place at the top of
@@ -204,4 +212,7 @@
204212
205213
206# Example configuration for intersphinx: refer to the Python standard library.214# Example configuration for intersphinx: refer to the Python standard library.
207intersphinx_mapping = {'http://docs.python.org/': None}215intersphinx_mapping = {'python': ('http://docs.python.org/', None),
216 'nova': ('http://nova.openstack.org', None),
217 'swift': ('http://swift.openstack.org', None),
218 'glance': ('http://glance.openstack.org', None)}
208219
=== modified file 'doc/source/index.rst'
--- doc/source/index.rst 2012-06-22 12:58:18 +0000
+++ doc/source/index.rst 2012-11-30 14:11:19 +0000
@@ -1,7 +1,7 @@
1Python bindings to the OpenStack Keystone API1Python bindings to the OpenStack Identity API (Keystone)
2==================================================2========================================================
33
4This is a client for OpenStack Keystone API. There's :doc:`a Python API4This is a client for OpenStack Identity API. There's :doc:`a Python API
5<using-api>` (the :mod:`keystoneclient` module), and a :doc:`command-line script5<using-api>` (the :mod:`keystoneclient` module), and a :doc:`command-line script
6<shell>` (installed as :program:`keystone`).6<shell>` (installed as :program:`keystone`).
77
@@ -10,20 +10,21 @@
10.. toctree::10.. toctree::
11 :maxdepth: 111 :maxdepth: 1
1212
13 releases
14 shell
13 using-api15 using-api
14 shell16
15 ref/index17 api/autoindex
16 releases
1718
18Contributing19Contributing
19============20============
2021
21Code is hosted `on GitHub`_. Submit bugs to the Keystone project on 22Code is hosted `on GitHub`_. Submit bugs to the Keystone project on
22`Launchpad`_. Submit code to the openstack/python-keystoneclient project using23`Launchpad`_. Submit code to the ``openstack/python-keystoneclient`` project
23`Gerrit`_.24using `Gerrit`_.
2425
25.. _on GitHub: https://github.com/openstack/python-keystoneclient26.. _on GitHub: https://github.com/openstack/python-keystoneclient
26.. _Launchpad: https://launchpad.net/keystone27.. _Launchpad: https://launchpad.net/python-keystoneclient
27.. _Gerrit: http://wiki.openstack.org/GerritWorkflow28.. _Gerrit: http://wiki.openstack.org/GerritWorkflow
2829
29Run tests with ``python setup.py test``.30Run tests with ``python setup.py test``.
3031
=== removed directory 'doc/source/ref'
=== removed file 'doc/source/ref/client.rst'
--- doc/source/ref/client.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/client.rst 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1Client
2======
3
4.. currentmodule:: keystoneclient.v2_0.client
5
6.. autoclass:: Client
7
8 .. automethod:: authenticate
90
=== removed file 'doc/source/ref/endpoints.rst'
--- doc/source/ref/endpoints.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/endpoints.rst 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1==============================
2Endpoint Manager and Endpoints
3==============================
4
5
6
7.. currentmodule:: keystoneclient.v2_0.endpoints
8
9.. automodule:: keystoneclient.v2_0.endpoints
10 :members:
11
120
=== removed file 'doc/source/ref/exceptions.rst'
--- doc/source/ref/exceptions.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/exceptions.rst 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
1Exceptions
2==========
3
4.. currentmodule:: keystoneclient.exceptions
5
6.. automodule:: keystoneclient.exceptions
7 :members:
8
90
=== removed file 'doc/source/ref/generic-client.rst'
--- doc/source/ref/generic-client.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/generic-client.rst 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1Generic client
2==============
3
4Use the generic client to obtain access to a specific endpoint version.
5
6
7.. currentmodule:: keystoneclient.generic.client
8
9.. autoclass:: Client
10
11 .. automethod:: discover
12
130
=== removed file 'doc/source/ref/index.rst'
--- doc/source/ref/index.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/index.rst 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
1API Reference
2=============
3
4The following API reference documents are available:
5
6.. toctree::
7 :maxdepth: 1
8
9 client
10 generic-client
11 tenants
12 users
13 roles
14 services
15 endpoints
16 exceptions
170
=== removed file 'doc/source/ref/roles.rst'
--- doc/source/ref/roles.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/roles.rst 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
1======================
2Role Manager and Roles
3======================
4
5.. currentmodule:: keystoneclient.v2_0.roles
6
7.. automodule:: keystoneclient.v2_0.roles
8 :members:
9
100
=== removed file 'doc/source/ref/services.rst'
--- doc/source/ref/services.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/services.rst 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1============================
2Service Manager and Services
3============================
4
5
6
7.. currentmodule:: keystoneclient.v2_0.services
8
9.. automodule:: keystoneclient.v2_0.services
10 :members:
11
120
=== removed file 'doc/source/ref/tenants.rst'
--- doc/source/ref/tenants.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/tenants.rst 1970-01-01 00:00:00 +0000
@@ -1,11 +0,0 @@
1==========================
2Tenant Manager and Tenants
3==========================
4
5
6
7.. currentmodule:: keystoneclient.v2_0.tenants
8
9.. automodule:: keystoneclient.v2_0.tenants
10 :members:
11
120
=== removed file 'doc/source/ref/users.rst'
--- doc/source/ref/users.rst 2012-06-22 12:58:18 +0000
+++ doc/source/ref/users.rst 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
1======================
2User Manager and Users
3======================
4
5.. currentmodule:: keystoneclient.v2_0.users
6
7.. automodule:: keystoneclient.v2_0.users
8 :members:
9
100
=== modified file 'doc/source/releases.rst'
--- doc/source/releases.rst 2012-06-22 12:58:18 +0000
+++ doc/source/releases.rst 2012-11-30 14:11:19 +0000
@@ -2,105 +2,32 @@
2Release notes2Release notes
3=============3=============
44
52.7.0 (October 21, 2011)50.1.3 (August 31, 2012)
6========================6=======================
7* Forked from http://github.com/rackspace/python-novaclient7* changed logging to report request and response independently in --debug mode
8* Rebranded to python-keystoneclient8* changed options to use hyphens instead of underscores
9* Refactored to support Keystone API (auth, tokens, services, roles, tenants,9* added support for PKI signed tokens with Keystone
10
11
120.1.2 (July 9, 2012)
13====================
14* added support for two-way SSL and --insecure option to allow for self-signed
15 certificates
16* added support for password prompting if not provided
17* added support for bash completion for keystone
18* updated CLI options to use dashes instead of underscores
19
200.1.1 (June 25, 2012)
21=====================
22* corrected versioning
23
240.1.0 (March 29, 2012)
25======================
26* released with OpenStack Essex and Diablo compatibility
27* forked from http://github.com/rackspace/python-novaclient
28* refactored to support Identity API (auth, tokens, services, roles, tenants,
10 users, etc.)29 users, etc.)
1130* removed legacy arguments of --username, --password, etc in migration to
122.5.8 (July 11, 2011)31 support a cross-openstack unified CLI convention defined at
13=====================32 http://wiki.openstack.org/UnifiedCLI
14* returns all public/private ips, not just first one33* required service ID for listing endpoints
15* better 'nova list' search options
16
172.5.7 - 2.5.6 = minor tweaks
18
192.5.5 (June 21, 2011)
20=====================
21* zone-boot min/max instance count added thanks to comstud
22* create for user added thanks to cerberus
23* fixed tests
24
252.5.3 (June 15, 2011)
26=====================
27* ProjectID can be None for backwards compatability.
28* README/docs updated for projectId thanks to usrleon
29
302.5.1 (June 10, 2011)
31=====================
32* ProjectID now part of authentication
33
342.5.0 (June 3, 2011)
35====================
36
37* better logging thanks to GridDynamics
38
392.4.4 (June 1, 2011)
40====================
41
42* added support for GET /servers with reservation_id (and /servers/detail)
43
442.4.3 (May 27, 2011)
45====================
46
47* added support for POST /zones/select (client only, not cmdline)
48
492.4 (March 7, 2011)
50===================
51
52* added Jacob Kaplan-Moss copyright notices to older/untouched files.
53
54
552.3 (March 2, 2011)
56===================
57
58* package renamed to python-novaclient. Module to novaclient
59
60
612.2 (March 1, 2011)
62===================
63
64* removed some license/copywrite notices from source that wasn't
65 significantly changed.
66
67
682.1 (Feb 28, 2011)
69==================
70
71* shell renamed to nova from novatools
72
73* license changed from BSD to Apache
74
752.0 (Feb 7, 2011)
76=================
77
78* Forked from https://github.com/jacobian/python-cloudservers
79
80* Rebranded to python-novatools
81
82* Auth URL support
83
84* New OpenStack specific commands added (pause, suspend, etc)
85
861.2 (August 15, 2010)
87=====================
88
89* Support for Python 2.4 - 2.7.
90
91* Improved output of :program:`cloudservers ipgroup-list`.
92
93* Made ``cloudservers boot --ipgroup <name>`` work (as well as ``--ipgroup
94 <id>``).
95
961.1 (May 6, 2010)
97=================
98
99* Added a ``--files`` option to :program:`cloudservers boot` supporting
100 the upload of (up to five) files at boot time.
101
102* Added a ``--key`` option to :program:`cloudservers boot` to key the server
103 with an SSH public key at boot time. This is just a shortcut for ``--files``,
104 but it's a useful shortcut.
105
106* Changed the default server image to Ubuntu 10.04 LTS.
10734
=== modified file 'doc/source/shell.rst'
--- doc/source/shell.rst 2012-09-07 13:13:18 +0000
+++ doc/source/shell.rst 2012-11-30 14:11:19 +0000
@@ -1,22 +1,43 @@
1The :program:`keystone` shell utility1The :program:`keystone` shell utility
2=========================================2=====================================
33
4.. program:: keystone4.. program:: keystone
5.. highlight:: bash5.. highlight:: bash
66
77
8The :program:`keystone` shell utility interacts with OpenStack Keystone API8The :program:`keystone` shell utility interacts with OpenStack Identity API
9from the command line. It supports the entirety of the OpenStack Keystone API.9from the command line. It supports the entirety of the OpenStack Identity API.
1010
11First, you'll need an OpenStack Keystone account. You get this by using the 11To communicate with the API, you will need to be authenticated - and the
12`keystone-manage` command in OpenStack Keystone.12:program:`keystone` provides multiple options for this.
1313
14You'll need to provide :program:`keystone` with your OpenStack username and14While bootstrapping keystone the authentication is accomplished with a
15password. You can do this with the :option:`--os-username`, :option:`--os-password`.15shared secret token and the location of the Identity API endpoint. The
16You can optionally specify a :option:`--os-tenant-id` or :option:`--os-tenant-name`,16shared secret token is configured in keystone.conf as "admin_token".
17to scope your token to a specific tenant. If you don't specify a tenant, you17
18will be scoped to your default tenant if you have one. Instead of using 18You can specify those values on the command line with :option:`--os-token`
19options, it is easier to just set them as environment variables:19and :option:`--os-endpoint`, or set them in environment variables:
20
21.. envvar:: OS_SERVICE_TOKEN
22
23 Your keystone administrative token
24
25.. envvar:: OS_SERVICE_ENDPOINT
26
27 Your Identity API endpoint
28
29The command line options will override any environment variables set.
30
31If you already have accounts, you can use your OpenStack username and
32password. You can do this with the :option:`--os-username`,
33:option:`--os-password`.
34
35Keystone allows a user to be associated with one or more tenants. To specify
36the tenant for which you want to authorize against, you may optionally
37specify a :option:`--os-tenant-id` or :option:`--os-tenant-name`.
38
39Instead of using options, it is easier to just set them as environment
40variables:
2041
21.. envvar:: OS_USERNAME42.. envvar:: OS_USERNAME
2243
2344
=== added directory 'doc/source/static'
=== added file 'doc/source/static/basic.css'
--- doc/source/static/basic.css 1970-01-01 00:00:00 +0000
+++ doc/source/static/basic.css 2012-11-30 14:11:19 +0000
@@ -0,0 +1,416 @@
1/**
2 * Sphinx stylesheet -- basic theme
3 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 */
5
6/* -- main layout ----------------------------------------------------------- */
7
8div.clearer {
9 clear: both;
10}
11
12/* -- relbar ---------------------------------------------------------------- */
13
14div.related {
15 width: 100%;
16 font-size: 90%;
17}
18
19div.related h3 {
20 display: none;
21}
22
23div.related ul {
24 margin: 0;
25 padding: 0 0 0 10px;
26 list-style: none;
27}
28
29div.related li {
30 display: inline;
31}
32
33div.related li.right {
34 float: right;
35 margin-right: 5px;
36}
37
38/* -- sidebar --------------------------------------------------------------- */
39
40div.sphinxsidebarwrapper {
41 padding: 10px 5px 0 10px;
42}
43
44div.sphinxsidebar {
45 float: left;
46 width: 230px;
47 margin-left: -100%;
48 font-size: 90%;
49}
50
51div.sphinxsidebar ul {
52 list-style: none;
53}
54
55div.sphinxsidebar ul ul,
56div.sphinxsidebar ul.want-points {
57 margin-left: 20px;
58 list-style: square;
59}
60
61div.sphinxsidebar ul ul {
62 margin-top: 0;
63 margin-bottom: 0;
64}
65
66div.sphinxsidebar form {
67 margin-top: 10px;
68}
69
70div.sphinxsidebar input {
71 border: 1px solid #98dbcc;
72 font-family: sans-serif;
73 font-size: 1em;
74}
75
76img {
77 border: 0;
78}
79
80/* -- search page ----------------------------------------------------------- */
81
82ul.search {
83 margin: 10px 0 0 20px;
84 padding: 0;
85}
86
87ul.search li {
88 padding: 5px 0 5px 20px;
89 background-image: url(file.png);
90 background-repeat: no-repeat;
91 background-position: 0 7px;
92}
93
94ul.search li a {
95 font-weight: bold;
96}
97
98ul.search li div.context {
99 color: #888;
100 margin: 2px 0 0 30px;
101 text-align: left;
102}
103
104ul.keywordmatches li.goodmatch a {
105 font-weight: bold;
106}
107
108/* -- index page ------------------------------------------------------------ */
109
110table.contentstable {
111 width: 90%;
112}
113
114table.contentstable p.biglink {
115 line-height: 150%;
116}
117
118a.biglink {
119 font-size: 1.3em;
120}
121
122span.linkdescr {
123 font-style: italic;
124 padding-top: 5px;
125 font-size: 90%;
126}
127
128/* -- general index --------------------------------------------------------- */
129
130table.indextable td {
131 text-align: left;
132 vertical-align: top;
133}
134
135table.indextable dl, table.indextable dd {
136 margin-top: 0;
137 margin-bottom: 0;
138}
139
140table.indextable tr.pcap {
141 height: 10px;
142}
143
144table.indextable tr.cap {
145 margin-top: 10px;
146 background-color: #f2f2f2;
147}
148
149img.toggler {
150 margin-right: 3px;
151 margin-top: 3px;
152 cursor: pointer;
153}
154
155/* -- general body styles --------------------------------------------------- */
156
157a.headerlink {
158 visibility: hidden;
159}
160
161h1:hover > a.headerlink,
162h2:hover > a.headerlink,
163h3:hover > a.headerlink,
164h4:hover > a.headerlink,
165h5:hover > a.headerlink,
166h6:hover > a.headerlink,
167dt:hover > a.headerlink {
168 visibility: visible;
169}
170
171div.body p.caption {
172 text-align: inherit;
173}
174
175div.body td {
176 text-align: left;
177}
178
179.field-list ul {
180 padding-left: 1em;
181}
182
183.first {
184}
185
186p.rubric {
187 margin-top: 30px;
188 font-weight: bold;
189}
190
191/* -- sidebars -------------------------------------------------------------- */
192
193div.sidebar {
194 margin: 0 0 0.5em 1em;
195 border: 1px solid #ddb;
196 padding: 7px 7px 0 7px;
197 background-color: #ffe;
198 width: 40%;
199 float: right;
200}
201
202p.sidebar-title {
203 font-weight: bold;
204}
205
206/* -- topics ---------------------------------------------------------------- */
207
208div.topic {
209 border: 1px solid #ccc;
210 padding: 7px 7px 0 7px;
211 margin: 10px 0 10px 0;
212}
213
214p.topic-title {
215 font-size: 1.1em;
216 font-weight: bold;
217 margin-top: 10px;
218}
219
220/* -- admonitions ----------------------------------------------------------- */
221
222div.admonition {
223 margin-top: 10px;
224 margin-bottom: 10px;
225 padding: 7px;
226}
227
228div.admonition dt {
229 font-weight: bold;
230}
231
232div.admonition dl {
233 margin-bottom: 0;
234}
235
236p.admonition-title {
237 margin: 0px 10px 5px 0px;
238 font-weight: bold;
239}
240
241div.body p.centered {
242 text-align: center;
243 margin-top: 25px;
244}
245
246/* -- tables ---------------------------------------------------------------- */
247
248table.docutils {
249 border: 0;
250 border-collapse: collapse;
251}
252
253table.docutils td, table.docutils th {
254 padding: 1px 8px 1px 0;
255 border-top: 0;
256 border-left: 0;
257 border-right: 0;
258 border-bottom: 1px solid #aaa;
259}
260
261table.field-list td, table.field-list th {
262 border: 0 !important;
263}
264
265table.footnote td, table.footnote th {
266 border: 0 !important;
267}
268
269th {
270 text-align: left;
271 padding-right: 5px;
272}
273
274/* -- other body styles ----------------------------------------------------- */
275
276dl {
277 margin-bottom: 15px;
278}
279
280dd p {
281 margin-top: 0px;
282}
283
284dd ul, dd table {
285 margin-bottom: 10px;
286}
287
288dd {
289 margin-top: 3px;
290 margin-bottom: 10px;
291 margin-left: 30px;
292}
293
294dt:target, .highlight {
295 background-color: #fbe54e;
296}
297
298dl.glossary dt {
299 font-weight: bold;
300 font-size: 1.1em;
301}
302
303.field-list ul {
304 margin: 0;
305 padding-left: 1em;
306}
307
308.field-list p {
309 margin: 0;
310}
311
312.refcount {
313 color: #060;
314}
315
316.optional {
317 font-size: 1.3em;
318}
319
320.versionmodified {
321 font-style: italic;
322}
323
324.system-message {
325 background-color: #fda;
326 padding: 5px;
327 border: 3px solid red;
328}
329
330.footnote:target {
331 background-color: #ffa
332}
333
334.line-block {
335 display: block;
336 margin-top: 1em;
337 margin-bottom: 1em;
338}
339
340.line-block .line-block {
341 margin-top: 0;
342 margin-bottom: 0;
343 margin-left: 1.5em;
344}
345
346/* -- code displays --------------------------------------------------------- */
347
348pre {
349 overflow: auto;
350}
351
352td.linenos pre {
353 padding: 5px 0px;
354 border: 0;
355 background-color: transparent;
356 color: #aaa;
357}
358
359table.highlighttable {
360 margin-left: 0.5em;
361}
362
363table.highlighttable td {
364 padding: 0 0.5em 0 0.5em;
365}
366
367tt.descname {
368 background-color: transparent;
369 font-weight: bold;
370 font-size: 1.2em;
371}
372
373tt.descclassname {
374 background-color: transparent;
375}
376
377tt.xref, a tt {
378 background-color: transparent;
379 font-weight: bold;
380}
381
382h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
383 background-color: transparent;
384}
385
386/* -- math display ---------------------------------------------------------- */
387
388img.math {
389 vertical-align: middle;
390}
391
392div.body div.math p {
393 text-align: center;
394}
395
396span.eqno {
397 float: right;
398}
399
400/* -- printout stylesheet --------------------------------------------------- */
401
402@media print {
403 div.document,
404 div.documentwrapper,
405 div.bodywrapper {
406 margin: 0 !important;
407 width: 100%;
408 }
409
410 div.sphinxsidebar,
411 div.related,
412 div.footer,
413 #top-link {
414 display: none;
415 }
416}
0417
=== added file 'doc/source/static/default.css'
--- doc/source/static/default.css 1970-01-01 00:00:00 +0000
+++ doc/source/static/default.css 2012-11-30 14:11:19 +0000
@@ -0,0 +1,230 @@
1/**
2 * Sphinx stylesheet -- default theme
3 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 */
5
6@import url("basic.css");
7
8/* -- page layout ----------------------------------------------------------- */
9
10body {
11 font-family: sans-serif;
12 font-size: 100%;
13 background-color: #11303d;
14 color: #000;
15 margin: 0;
16 padding: 0;
17}
18
19div.document {
20 background-color: #1c4e63;
21}
22
23div.documentwrapper {
24 float: left;
25 width: 100%;
26}
27
28div.bodywrapper {
29 margin: 0 0 0 230px;
30}
31
32div.body {
33 background-color: #ffffff;
34 color: #000000;
35 padding: 0 20px 30px 20px;
36}
37
38div.footer {
39 color: #ffffff;
40 width: 100%;
41 padding: 9px 0 9px 0;
42 text-align: center;
43 font-size: 75%;
44}
45
46div.footer a {
47 color: #ffffff;
48 text-decoration: underline;
49}
50
51div.related {
52 background-color: #133f52;
53 line-height: 30px;
54 color: #ffffff;
55}
56
57div.related a {
58 color: #ffffff;
59}
60
61div.sphinxsidebar {
62}
63
64div.sphinxsidebar h3 {
65 font-family: 'Trebuchet MS', sans-serif;
66 color: #ffffff;
67 font-size: 1.4em;
68 font-weight: normal;
69 margin: 0;
70 padding: 0;
71}
72
73div.sphinxsidebar h3 a {
74 color: #ffffff;
75}
76
77div.sphinxsidebar h4 {
78 font-family: 'Trebuchet MS', sans-serif;
79 color: #ffffff;
80 font-size: 1.3em;
81 font-weight: normal;
82 margin: 5px 0 0 0;
83 padding: 0;
84}
85
86div.sphinxsidebar p {
87 color: #ffffff;
88}
89
90div.sphinxsidebar p.topless {
91 margin: 5px 10px 10px 10px;
92}
93
94div.sphinxsidebar ul {
95 margin: 10px;
96 padding: 0;
97 color: #ffffff;
98}
99
100div.sphinxsidebar a {
101 color: #98dbcc;
102}
103
104div.sphinxsidebar input {
105 border: 1px solid #98dbcc;
106 font-family: sans-serif;
107 font-size: 1em;
108}
109
110/* -- body styles ----------------------------------------------------------- */
111
112a {
113 color: #355f7c;
114 text-decoration: none;
115}
116
117a:hover {
118 text-decoration: underline;
119}
120
121div.body p, div.body dd, div.body li {
122 text-align: left;
123 line-height: 130%;
124}
125
126div.body h1,
127div.body h2,
128div.body h3,
129div.body h4,
130div.body h5,
131div.body h6 {
132 font-family: 'Trebuchet MS', sans-serif;
133 background-color: #f2f2f2;
134 font-weight: normal;
135 color: #20435c;
136 border-bottom: 1px solid #ccc;
137 margin: 20px -20px 10px -20px;
138 padding: 3px 0 3px 10px;
139}
140
141div.body h1 { margin-top: 0; font-size: 200%; }
142div.body h2 { font-size: 160%; }
143div.body h3 { font-size: 140%; }
144div.body h4 { font-size: 120%; }
145div.body h5 { font-size: 110%; }
146div.body h6 { font-size: 100%; }
147
148a.headerlink {
149 color: #c60f0f;
150 font-size: 0.8em;
151 padding: 0 4px 0 4px;
152 text-decoration: none;
153}
154
155a.headerlink:hover {
156 background-color: #c60f0f;
157 color: white;
158}
159
160div.body p, div.body dd, div.body li {
161 text-align: left;
162 line-height: 130%;
163}
164
165div.admonition p.admonition-title + p {
166 display: inline;
167}
168
169div.admonition p {
170 margin-bottom: 5px;
171}
172
173div.admonition pre {
174 margin-bottom: 5px;
175}
176
177div.admonition ul, div.admonition ol {
178 margin-bottom: 5px;
179}
180
181div.note {
182 background-color: #eee;
183 border: 1px solid #ccc;
184}
185
186div.seealso {
187 background-color: #ffc;
188 border: 1px solid #ff6;
189}
190
191div.topic {
192 background-color: #eee;
193}
194
195div.warning {
196 background-color: #ffe4e4;
197 border: 1px solid #f66;
198}
199
200p.admonition-title {
201 display: inline;
202}
203
204p.admonition-title:after {
205 content: ":";
206}
207
208pre {
209 padding: 5px;
210 background-color: #eeffcc;
211 color: #333333;
212 line-height: 120%;
213 border: 1px solid #ac9;
214 border-left: none;
215 border-right: none;
216}
217
218tt {
219 background-color: #ecf0f3;
220 padding: 0 1px 0 1px;
221 font-size: 0.95em;
222}
223
224.warning tt {
225 background: #efc2c2;
226}
227
228.note tt {
229 background: #d6d6d6;
230}
0231
=== added file 'doc/source/static/header-line.gif'
1Binary files doc/source/static/header-line.gif 1970-01-01 00:00:00 +0000 and doc/source/static/header-line.gif 2012-11-30 14:11:19 +0000 differ232Binary files doc/source/static/header-line.gif 1970-01-01 00:00:00 +0000 and doc/source/static/header-line.gif 2012-11-30 14:11:19 +0000 differ
=== added file 'doc/source/static/header_bg.jpg'
2Binary files doc/source/static/header_bg.jpg 1970-01-01 00:00:00 +0000 and doc/source/static/header_bg.jpg 2012-11-30 14:11:19 +0000 differ233Binary files doc/source/static/header_bg.jpg 1970-01-01 00:00:00 +0000 and doc/source/static/header_bg.jpg 2012-11-30 14:11:19 +0000 differ
=== added file 'doc/source/static/jquery.tweet.js'
--- doc/source/static/jquery.tweet.js 1970-01-01 00:00:00 +0000
+++ doc/source/static/jquery.tweet.js 2012-11-30 14:11:19 +0000
@@ -0,0 +1,154 @@
1(function($) {
2
3 $.fn.tweet = function(o){
4 var s = {
5 username: ["seaofclouds"], // [string] required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
6 list: null, //[string] optional name of list belonging to username
7 avatar_size: null, // [integer] height and width of avatar if displayed (48px max)
8 count: 3, // [integer] how many tweets to display?
9 intro_text: null, // [string] do you want text BEFORE your your tweets?
10 outro_text: null, // [string] do you want text AFTER your tweets?
11 join_text: null, // [string] optional text in between date and tweet, try setting to "auto"
12 auto_join_text_default: "i said,", // [string] auto text for non verb: "i said" bullocks
13 auto_join_text_ed: "i", // [string] auto text for past tense: "i" surfed
14 auto_join_text_ing: "i am", // [string] auto tense for present tense: "i was" surfing
15 auto_join_text_reply: "i replied to", // [string] auto tense for replies: "i replied to" @someone "with"
16 auto_join_text_url: "i was looking at", // [string] auto tense for urls: "i was looking at" http:...
17 loading_text: null, // [string] optional loading text, displayed while tweets load
18 query: null // [string] optional search query
19 };
20
21 if(o) $.extend(s, o);
22
23 $.fn.extend({
24 linkUrl: function() {
25 var returning = [];
26 var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
27 this.each(function() {
28 returning.push(this.replace(regexp,"<a href=\"$1\">$1</a>"));
29 });
30 return $(returning);
31 },
32 linkUser: function() {
33 var returning = [];
34 var regexp = /[\@]+([A-Za-z0-9-_]+)/gi;
35 this.each(function() {
36 returning.push(this.replace(regexp,"<a href=\"http://twitter.com/$1\">@$1</a>"));
37 });
38 return $(returning);
39 },
40 linkHash: function() {
41 var returning = [];
42 var regexp = / [\#]+([A-Za-z0-9-_]+)/gi;
43 this.each(function() {
44 returning.push(this.replace(regexp, ' <a href="http://search.twitter.com/search?q=&tag=$1&lang=all&from='+s.username.join("%2BOR%2B")+'">#$1</a>'));
45 });
46 return $(returning);
47 },
48 capAwesome: function() {
49 var returning = [];
50 this.each(function() {
51 returning.push(this.replace(/\b(awesome)\b/gi, '<span class="awesome">$1</span>'));
52 });
53 return $(returning);
54 },
55 capEpic: function() {
56 var returning = [];
57 this.each(function() {
58 returning.push(this.replace(/\b(epic)\b/gi, '<span class="epic">$1</span>'));
59 });
60 return $(returning);
61 },
62 makeHeart: function() {
63 var returning = [];
64 this.each(function() {
65 returning.push(this.replace(/(&lt;)+[3]/gi, "<tt class='heart'>&#x2665;</tt>"));
66 });
67 return $(returning);
68 }
69 });
70
71 function relative_time(time_value) {
72 var parsed_date = Date.parse(time_value);
73 var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
74 var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
75 var pluralize = function (singular, n) {
76 return '' + n + ' ' + singular + (n == 1 ? '' : 's');
77 };
78 if(delta < 60) {
79 return 'less than a minute ago';
80 } else if(delta < (45*60)) {
81 return 'about ' + pluralize("minute", parseInt(delta / 60)) + ' ago';
82 } else if(delta < (24*60*60)) {
83 return 'about ' + pluralize("hour", parseInt(delta / 3600)) + ' ago';
84 } else {
85 return 'about ' + pluralize("day", parseInt(delta / 86400)) + ' ago';
86 }
87 }
88
89 function build_url() {
90 var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
91 if (s.list) {
92 return proto+"//api.twitter.com/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?";
93 } else if (s.query == null && s.username.length == 1) {
94 return proto+'//twitter.com/status/user_timeline/'+s.username[0]+'.json?count='+s.count+'&callback=?';
95 } else {
96 var query = (s.query || 'from:'+s.username.join('%20OR%20from:'));
97 return proto+'//search.twitter.com/search.json?&q='+query+'&rpp='+s.count+'&callback=?';
98 }
99 }
100
101 return this.each(function(){
102 var list = $('<ul class="tweet_list">').appendTo(this);
103 var intro = '<p class="tweet_intro">'+s.intro_text+'</p>';
104 var outro = '<p class="tweet_outro">'+s.outro_text+'</p>';
105 var loading = $('<p class="loading">'+s.loading_text+'</p>');
106
107 if(typeof(s.username) == "string"){
108 s.username = [s.username];
109 }
110
111 if (s.loading_text) $(this).append(loading);
112 $.getJSON(build_url(), function(data){
113 if (s.loading_text) loading.remove();
114 if (s.intro_text) list.before(intro);
115 $.each((data.results || data), function(i,item){
116 // auto join text based on verb tense and content
117 if (s.join_text == "auto") {
118 if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
119 var join_text = s.auto_join_text_reply;
120 } else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
121 var join_text = s.auto_join_text_url;
122 } else if (item.text.match(/^((\w+ed)|just) .*/im)) {
123 var join_text = s.auto_join_text_ed;
124 } else if (item.text.match(/^(\w*ing) .*/i)) {
125 var join_text = s.auto_join_text_ing;
126 } else {
127 var join_text = s.auto_join_text_default;
128 }
129 } else {
130 var join_text = s.join_text;
131 };
132
133 var from_user = item.from_user || item.user.screen_name;
134 var profile_image_url = item.profile_image_url || item.user.profile_image_url;
135 var join_template = '<span class="tweet_join"> '+join_text+' </span>';
136 var join = ((s.join_text) ? join_template : ' ');
137 var avatar_template = '<a class="tweet_avatar" href="http://twitter.com/'+from_user+'"><img src="'+profile_image_url+'" height="'+s.avatar_size+'" width="'+s.avatar_size+'" alt="'+from_user+'\'s avatar" title="'+from_user+'\'s avatar" border="0"/></a>';
138 var avatar = (s.avatar_size ? avatar_template : '');
139 var date = '<a href="http://twitter.com/'+from_user+'/statuses/'+item.id+'" title="view tweet on twitter">'+relative_time(item.created_at)+'</a>';
140 var text = '<span class="tweet_text">' +$([item.text]).linkUrl().linkUser().linkHash().makeHeart().capAwesome().capEpic()[0]+ '</span>';
141
142 // until we create a template option, arrange the items below to alter a tweet's display.
143 list.append('<li>' + avatar + date + join + text + '</li>');
144
145 list.children('li:first').addClass('tweet_first');
146 list.children('li:odd').addClass('tweet_even');
147 list.children('li:even').addClass('tweet_odd');
148 });
149 if (s.outro_text) list.after(outro);
150 });
151
152 });
153 };
154})(jQuery);
0\ No newline at end of file155\ No newline at end of file
1156
=== added file 'doc/source/static/nature.css'
--- doc/source/static/nature.css 1970-01-01 00:00:00 +0000
+++ doc/source/static/nature.css 2012-11-30 14:11:19 +0000
@@ -0,0 +1,245 @@
1/*
2 * nature.css_t
3 * ~~~~~~~~~~~~
4 *
5 * Sphinx stylesheet -- nature theme.
6 *
7 * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
8 * :license: BSD, see LICENSE for details.
9 *
10 */
11
12@import url("basic.css");
13
14/* -- page layout ----------------------------------------------------------- */
15
16body {
17 font-family: Arial, sans-serif;
18 font-size: 100%;
19 background-color: #111;
20 color: #555;
21 margin: 0;
22 padding: 0;
23}
24
25div.documentwrapper {
26 float: left;
27 width: 100%;
28}
29
30div.bodywrapper {
31 margin: 0 0 0 {{ theme_sidebarwidth|toint }}px;
32}
33
34hr {
35 border: 1px solid #B1B4B6;
36}
37
38div.document {
39 background-color: #eee;
40}
41
42div.body {
43 background-color: #ffffff;
44 color: #3E4349;
45 padding: 0 30px 30px 30px;
46 font-size: 0.9em;
47}
48
49div.footer {
50 color: #555;
51 width: 100%;
52 padding: 13px 0;
53 text-align: center;
54 font-size: 75%;
55}
56
57div.footer a {
58 color: #444;
59 text-decoration: underline;
60}
61
62div.related {
63 background-color: #6BA81E;
64 line-height: 32px;
65 color: #fff;
66 text-shadow: 0px 1px 0 #444;
67 font-size: 0.9em;
68}
69
70div.related a {
71 color: #E2F3CC;
72}
73
74div.sphinxsidebar {
75 font-size: 0.75em;
76 line-height: 1.5em;
77}
78
79div.sphinxsidebarwrapper{
80 padding: 20px 0;
81}
82
83div.sphinxsidebar h3,
84div.sphinxsidebar h4 {
85 font-family: Arial, sans-serif;
86 color: #222;
87 font-size: 1.2em;
88 font-weight: normal;
89 margin: 0;
90 padding: 5px 10px;
91 background-color: #ddd;
92 text-shadow: 1px 1px 0 white
93}
94
95div.sphinxsidebar h4{
96 font-size: 1.1em;
97}
98
99div.sphinxsidebar h3 a {
100 color: #444;
101}
102
103
104div.sphinxsidebar p {
105 color: #888;
106 padding: 5px 20px;
107}
108
109div.sphinxsidebar p.topless {
110}
111
112div.sphinxsidebar ul {
113 margin: 10px 20px;
114 padding: 0;
115 color: #000;
116}
117
118div.sphinxsidebar a {
119 color: #444;
120}
121
122div.sphinxsidebar input {
123 border: 1px solid #ccc;
124 font-family: sans-serif;
125 font-size: 1em;
126}
127
128div.sphinxsidebar input[type=text]{
129 margin-left: 20px;
130}
131
132/* -- body styles ----------------------------------------------------------- */
133
134a {
135 color: #005B81;
136 text-decoration: none;
137}
138
139a:hover {
140 color: #E32E00;
141 text-decoration: underline;
142}
143
144div.body h1,
145div.body h2,
146div.body h3,
147div.body h4,
148div.body h5,
149div.body h6 {
150 font-family: Arial, sans-serif;
151 background-color: #BED4EB;
152 font-weight: normal;
153 color: #212224;
154 margin: 30px 0px 10px 0px;
155 padding: 5px 0 5px 10px;
156 text-shadow: 0px 1px 0 white
157}
158
159div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
160div.body h2 { font-size: 150%; background-color: #C8D5E3; }
161div.body h3 { font-size: 120%; background-color: #D8DEE3; }
162div.body h4 { font-size: 110%; background-color: #D8DEE3; }
163div.body h5 { font-size: 100%; background-color: #D8DEE3; }
164div.body h6 { font-size: 100%; background-color: #D8DEE3; }
165
166a.headerlink {
167 color: #c60f0f;
168 font-size: 0.8em;
169 padding: 0 4px 0 4px;
170 text-decoration: none;
171}
172
173a.headerlink:hover {
174 background-color: #c60f0f;
175 color: white;
176}
177
178div.body p, div.body dd, div.body li {
179 line-height: 1.5em;
180}
181
182div.admonition p.admonition-title + p {
183 display: inline;
184}
185
186div.highlight{
187 background-color: white;
188}
189
190div.note {
191 background-color: #eee;
192 border: 1px solid #ccc;
193}
194
195div.seealso {
196 background-color: #ffc;
197 border: 1px solid #ff6;
198}
199
200div.topic {
201 background-color: #eee;
202}
203
204div.warning {
205 background-color: #ffe4e4;
206 border: 1px solid #f66;
207}
208
209p.admonition-title {
210 display: inline;
211}
212
213p.admonition-title:after {
214 content: ":";
215}
216
217pre {
218 padding: 10px;
219 background-color: White;
220 color: #222;
221 line-height: 1.2em;
222 border: 1px solid #C6C9CB;
223 font-size: 1.1em;
224 margin: 1.5em 0 1.5em 0;
225 -webkit-box-shadow: 1px 1px 1px #d8d8d8;
226 -moz-box-shadow: 1px 1px 1px #d8d8d8;
227}
228
229tt {
230 background-color: #ecf0f3;
231 color: #222;
232 /* padding: 1px 2px; */
233 font-size: 1.1em;
234 font-family: monospace;
235}
236
237.viewcode-back {
238 font-family: Arial, sans-serif;
239}
240
241div.viewcode-block:target {
242 background-color: #f4debf;
243 border-top: 1px solid #ac9;
244 border-bottom: 1px solid #ac9;
245}
0246
=== added file 'doc/source/static/openstack_logo.png'
1Binary files doc/source/static/openstack_logo.png 1970-01-01 00:00:00 +0000 and doc/source/static/openstack_logo.png 2012-11-30 14:11:19 +0000 differ247Binary files doc/source/static/openstack_logo.png 1970-01-01 00:00:00 +0000 and doc/source/static/openstack_logo.png 2012-11-30 14:11:19 +0000 differ
=== added file 'doc/source/static/tweaks.css'
--- doc/source/static/tweaks.css 1970-01-01 00:00:00 +0000
+++ doc/source/static/tweaks.css 2012-11-30 14:11:19 +0000
@@ -0,0 +1,94 @@
1body {
2 background: #fff url(../_static/header_bg.jpg) top left no-repeat;
3}
4
5#header {
6 width: 950px;
7 margin: 0 auto;
8 height: 102px;
9}
10
11#header h1#logo {
12 background: url(../_static/openstack_logo.png) top left no-repeat;
13 display: block;
14 float: left;
15 text-indent: -9999px;
16 width: 175px;
17 height: 55px;
18}
19
20#navigation {
21 background: url(../_static/header-line.gif) repeat-x 0 bottom;
22 display: block;
23 float: left;
24 margin: 27px 0 0 25px;
25 padding: 0;
26}
27
28#navigation li{
29 float: left;
30 display: block;
31 margin-right: 25px;
32}
33
34#navigation li a {
35 display: block;
36 font-weight: normal;
37 text-decoration: none;
38 background-position: 50% 0;
39 padding: 20px 0 5px;
40 color: #353535;
41 font-size: 14px;
42}
43
44#navigation li a.current, #navigation li a.section {
45 border-bottom: 3px solid #cf2f19;
46 color: #cf2f19;
47}
48
49div.related {
50 background-color: #cde2f8;
51 border: 1px solid #b0d3f8;
52}
53
54div.related a {
55 color: #4078ba;
56 text-shadow: none;
57}
58
59div.sphinxsidebarwrapper {
60 padding-top: 0;
61}
62
63pre {
64 color: #555;
65}
66
67div.documentwrapper h1, div.documentwrapper h2, div.documentwrapper h3, div.documentwrapper h4, div.documentwrapper h5, div.documentwrapper h6 {
68 font-family: 'PT Sans', sans-serif !important;
69 color: #264D69;
70 border-bottom: 1px dotted #C5E2EA;
71 padding: 0;
72 background: none;
73 padding-bottom: 5px;
74}
75
76div.documentwrapper h3 {
77 color: #CF2F19;
78}
79
80a.headerlink {
81 color: #fff !important;
82 margin-left: 5px;
83 background: #CF2F19 !important;
84}
85
86div.body {
87 margin-top: -25px;
88 margin-left: 230px;
89}
90
91div.document {
92 width: 960px;
93 margin: 0 auto;
94}
0\ No newline at end of file95\ No newline at end of file
196
=== modified file 'doc/source/using-api.rst'
--- doc/source/using-api.rst 2012-06-22 12:58:18 +0000
+++ doc/source/using-api.rst 2012-11-30 14:11:19 +0000
@@ -4,7 +4,8 @@
44
5Introduction5Introduction
6============6============
7The main concepts in the Keystone API are:7
8The main concepts in the Identity API are:
89
9 * tenants10 * tenants
10 * users11 * users
@@ -12,12 +13,13 @@
12 * services13 * services
13 * endpoints14 * endpoints
1415
15The Keystone API lets you query and make changes through managers. For example,16The Identity API lets you query and make changes through managers. For example,
16to maipulate tenants, you interact with a17to manipulate tenants, you interact with a
17``keystoneclient.v2_0.tenants.TenantManger`` object.18``keystoneclient.v2_0.tenants.TenantManager`` object.
1819
19You obtain access to managers through via atributes of the ``keystoneclient.v2_0.client.Client`` object. For example, the ``tenants`` attribute of the ``Client``20You obtain access to managers through via attributes of the
20class is a tenant manager::21``keystoneclient.v2_0.client.Client`` object. For example, the ``tenants``
22attribute of the ``Client`` class is a tenant manager::
2123
22 >>> from keystoneclient.v2_0 import client24 >>> from keystoneclient.v2_0 import client
23 >>> keystone = client.Client(...)25 >>> keystone = client.Client(...)
@@ -36,8 +38,8 @@
3638
37If you are an administrator, you can authenticate by connecting to the admin39If you are an administrator, you can authenticate by connecting to the admin
38endpoint and using the admin token (sometimes referred to as the service40endpoint and using the admin token (sometimes referred to as the service
39token). The token is specified as the ``admin_token`` configuration option in your41token). The token is specified as the ``admin_token`` configuration option in
40keystone.conf config file, which is typically in /etc/keystone::42your keystone.conf config file, which is typically in /etc/keystone::
4143
42 >>> from keystoneclient.v2_0 import client44 >>> from keystoneclient.v2_0 import client
43 >>> token = '012345SECRET99TOKEN012345'45 >>> token = '012345SECRET99TOKEN012345'
@@ -54,7 +56,7 @@
54 >>> tenant_name='openstackDemo'56 >>> tenant_name='openstackDemo'
55 >>> auth_url='http://192.168.206.130:5000/v2.0'57 >>> auth_url='http://192.168.206.130:5000/v2.0'
56 >>> keystone = client.Client(username=username, password=password,58 >>> keystone = client.Client(username=username, password=password,
57 ... tenant_name, auth_url=auth_url)59 ... tenant_name=tenant_name, auth_url=auth_url)
5860
59Creating tenants61Creating tenants
60================62================
@@ -77,8 +79,9 @@
77 >>> keystone = client.Client(...)79 >>> keystone = client.Client(...)
78 >>> tenants = keystone.tenants.list()80 >>> tenants = keystone.tenants.list()
79 >>> my_tenant = [x for x in tenants if x.name=='openstackDemo'][0]81 >>> my_tenant = [x for x in tenants if x.name=='openstackDemo'][0]
80 >>> my_user = keystone.users.create(name="adminUser", password="secretword",82 >>> my_user = keystone.users.create(name="adminUser",
81 ... tenant_id=my_tenant.id)83 ... password="secretword",
84 ... tenant_id=my_tenant.id)
8285
83Creating roles and adding users86Creating roles and adding users
84===============================87===============================
@@ -103,7 +106,8 @@
103 >>> keystone = client.Client(...)106 >>> keystone = client.Client(...)
104 >>> service = keystone.services.create(name="nova", service_type="compute",107 >>> service = keystone.services.create(name="nova", service_type="compute",
105 ... description="Nova Compute Service")108 ... description="Nova Compute Service")
106 >>> keystone.endpoints.create(region="RegionOne", service_id=service.id,109 >>> keystone.endpoints.create(
107 ... publicurl="http://192.168.206.130:8774/v2/%(tenant_id)s",110 ... region="RegionOne", service_id=service.id,
108 ... adminurl="http://192.168.206.130:8774/v2/%(tenant_id)s",111 ... publicurl="http://192.168.206.130:8774/v2/%(tenant_id)s",
109 ... internalurl="http://192.168.206.130:8774/v2/%(tenant_id)s")112 ... adminurl="http://192.168.206.130:8774/v2/%(tenant_id)s",
113 ... internalurl="http://192.168.206.130:8774/v2/%(tenant_id)s")
110114
=== added directory 'examples'
=== added directory 'examples/pki'
=== added directory 'examples/pki/certs'
=== added file 'examples/pki/certs/cacert.pem'
--- examples/pki/certs/cacert.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/certs/cacert.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,18 @@
1-----BEGIN CERTIFICATE-----
2MIIC0TCCAjqgAwIBAgIJAP2TNFqmE1KUMA0GCSqGSIb3DQEBBQUAMIGeMQowCAYD
3VQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55
4dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMG
5CSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2Vs
6ZiBTaWduZWQwIBcNMTIxMTExMTA1NDA2WhgPMjA3MTA1MDYxMDU0MDZaMIGeMQow
7CAYDVQQFEwE1MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1
8bm55dmFsZTESMBAGA1UEChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTEl
9MCMGCSqGSIb3DQEJARYWa2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxML
10U2VsZiBTaWduZWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMXgnd5wlHAp
11GxZ58LrpEkHU995lT9PxtMgkp0tpFhg7R5HQw9K7TfQk5NHB28hNzf8UE/c0z2pJ
12XggPnAzvdx27NQeJGX5CWsi6fITZ8vH/+SxgfxxC+CE/6BkDpzw21MgBtq11vWL7
13XVaxNeU12Ax889U66i3CrObuCYt2mbpzAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
14Af8wDQYJKoZIhvcNAQEFBQADgYEAkFIbnr2/0/XWp+f80Gl6GAC7tdmZFlT9udVF
15q794rXyMlYY64pq34SzfQAn+4DztT4B9yzrTx03tLNr6Uf+5TS+ubcwG41UBBMs/
16Icf9zBMRqr+IXhijS49gQ7dPjqNTCqX+6ILbRWjdXP15ZWymI3ayQL/CMwFt/E+0
17kT6MLes=
18-----END CERTIFICATE-----
019
=== added file 'examples/pki/certs/middleware.pem'
--- examples/pki/certs/middleware.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/certs/middleware.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,33 @@
1-----BEGIN CERTIFICATE-----
2MIICoTCCAgoCARAwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV
3BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK
4EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr
5ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x
6MjExMTExMDU0MDZaGA8yMDcxMDUwNjEwNTQwNlowgZAxCzAJBgNVBAYTAlVTMQsw
7CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh
8Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv
9cGVuc3RhY2sub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEB
10BQADgY0AMIGJAoGBALVu4bjaOH33yAx0WdpEqj4UDVsLxVjWxEpIbOlDlc6IfJd+
11cUriQtxf6ahjxtzLPERS81SnwZmrICWZngbOn733pULMTZktTJH+o7C74NdKwUSN
12xjlCeWUy+FqIQoje4ygoJRPpMdkp1wHNO0ZERwRN9e8M5TIlx/LRtk+q8bT5AgMB
13AAEwDQYJKoZIhvcNAQEFBQADgYEAcp9ancue9Oq+MkaPucCrIqFhiUsdUThulJlB
14etPpUDGgStBSHgze/oxG2+flIjRoI6gG9Chfw//vWHOwDT7N32AHSgaI4b8/k/+s
15hAV2khYkV4PW2oS1TfeU/vxQzXbgApqhLBNqfFmJVW48aGAr/aqsJi3MYWN3269+
166vChaVw=
17-----END CERTIFICATE-----
18-----BEGIN PRIVATE KEY-----
19MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALVu4bjaOH33yAx0
20WdpEqj4UDVsLxVjWxEpIbOlDlc6IfJd+cUriQtxf6ahjxtzLPERS81SnwZmrICWZ
21ngbOn733pULMTZktTJH+o7C74NdKwUSNxjlCeWUy+FqIQoje4ygoJRPpMdkp1wHN
22O0ZERwRN9e8M5TIlx/LRtk+q8bT5AgMBAAECgYAmwq6EYFJrTvE0//JmN/8qzfvg
23dI5PoWpD+F8UInUxr2T2tHOdrOLd07vGVrKYXu7cJeCIOGKa4r02azAggioL/nE9
24FgPpqEC+QROvLuhFsk1gLZ2pGQ06sveKZVMH22h59BKZkYlhjh5qd4vlmhPqkmPp
25gdXj7ZjDCJhhQdFVkQJBANp18k2mVksn8q29LMieVTSIZNN3ucDA1QHbim+3fp/O
26GxCzU7Mv1Xfnu1zoRFu5/sF3YG0Zy3TGPDrEljBC3rUCQQDUnBjVFXL35OkBZqXW
27taJPzGbsPoqAO+Ls2juS97zNzeGxUNhvcKuEvHO63PXqDxp1535DpvJEBN1rT2FF
28iaO1AkEAt/QTWWFUTqrPxY6DNFdm5fpn9E1fg7icZJkKBDJeFJCH59MpCryfovzl
29n0ERtq9ynlQ4RQYwdR8rvkylLvRP9QJAOiXHFOAc5XeR0nREfwiGL9TzgUFJl/DJ
30C4ZULMnctVzNkTVPPItQHal87WppR26CCiUZ/161e6zo8eRv8hjG0QJABWqfYQuK
31dWH8nxlXS+NFUDbsCdL+XpOVE7iEH7hvSw/A/kz40mLx8sDp/Fz1ysrogR/L+NGC
32Vrlwm4q/WYJO0Q==
33-----END PRIVATE KEY-----
034
=== added file 'examples/pki/certs/signing_cert.pem'
--- examples/pki/certs/signing_cert.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/certs/signing_cert.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,17 @@
1-----BEGIN CERTIFICATE-----
2MIICoDCCAgkCAREwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV
3BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK
4EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr
5ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x
6MjExMTExMDU0MDZaGA8yMDcxMDUwNjEwNTQwNlowgY8xCzAJBgNVBAYTAlVTMQsw
7CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh
8Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv
9cGVuc3RhY2sub3JnMREwDwYDVQQDEwhLZXlzdG9uZTCBnzANBgkqhkiG9w0BAQEF
10AAOBjQAwgYkCgYEAuoQC6IBqMxC5845c/ZkLsdcQbTHqIpYJHEkwEoxyeEjwiGFf
11iZmiZ91pSFNc9MfjdJnN+be/ndVS19w1nrrJvV/udVsf6JZWkTPX5HyxnllwznCH
12pP7gfvMZzGsqzWlSdiD6mcRbCYRX9hCCauG3jhCtISINCVYMYQGH6QSib9sCAwEA
13ATANBgkqhkiG9w0BAQUFAAOBgQBCssELi+1RSjEmzeqSnpgUqmtpvB9oxbcwl+xH
14rIrYvqMU6pV2aSxgLDqpGjjusLHUau9Bmu3Myc/fm9/mlPUQHNj0AWl8vvfSlq1b
15vsWMUa1h4UFlPWoF2DIUFd+noBxe5CbcLUV6K0oyJAcPO433OyuGl5oQkhxmoy1J
16w59KRg==
17-----END CERTIFICATE-----
018
=== added file 'examples/pki/certs/ssl_cert.pem'
--- examples/pki/certs/ssl_cert.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/certs/ssl_cert.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,17 @@
1-----BEGIN CERTIFICATE-----
2MIICoTCCAgoCARAwDQYJKoZIhvcNAQEFBQAwgZ4xCjAIBgNVBAUTATUxCzAJBgNV
3BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQK
4EwlPcGVuU3RhY2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZr
5ZXlzdG9uZUBvcGVuc3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZDAgFw0x
6MjExMTExMDU0MDZaGA8yMDcxMDUwNjEwNTQwNlowgZAxCzAJBgNVBAYTAlVTMQsw
7CQYDVQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3Rh
8Y2sxETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBv
9cGVuc3RhY2sub3JnMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEB
10BQADgY0AMIGJAoGBALVu4bjaOH33yAx0WdpEqj4UDVsLxVjWxEpIbOlDlc6IfJd+
11cUriQtxf6ahjxtzLPERS81SnwZmrICWZngbOn733pULMTZktTJH+o7C74NdKwUSN
12xjlCeWUy+FqIQoje4ygoJRPpMdkp1wHNO0ZERwRN9e8M5TIlx/LRtk+q8bT5AgMB
13AAEwDQYJKoZIhvcNAQEFBQADgYEAcp9ancue9Oq+MkaPucCrIqFhiUsdUThulJlB
14etPpUDGgStBSHgze/oxG2+flIjRoI6gG9Chfw//vWHOwDT7N32AHSgaI4b8/k/+s
15hAV2khYkV4PW2oS1TfeU/vxQzXbgApqhLBNqfFmJVW48aGAr/aqsJi3MYWN3269+
166vChaVw=
17-----END CERTIFICATE-----
018
=== added directory 'examples/pki/cms'
=== added file 'examples/pki/cms/auth_token_revoked.json'
--- examples/pki/cms/auth_token_revoked.json 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/auth_token_revoked.json 2012-11-30 14:11:19 +0000
@@ -0,0 +1,1 @@
1{"access": {"serviceCatalog": [{"endpoints": [{"adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", "region": "regionOne", "internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", "publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a"}], "endpoints_links": [], "type": "volume", "name": "volume"}, {"endpoints": [{"adminURL": "http://127.0.0.1:9292/v1", "region": "regionOne", "internalURL": "http://127.0.0.1:9292/v1", "publicURL": "http://127.0.0.1:9292/v1"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", "region": "regionOne", "internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", "publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a"}], "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://127.0.0.1:35357/v2.0", "region": "RegionOne", "internalURL": "http://127.0.0.1:35357/v2.0", "publicURL": "http://127.0.0.1:5000/v2.0"}], "endpoints_links": [], "type": "identity", "name": "keystone"}],"token": {"expires": "2012-06-02T14:47:34Z", "id": "placeholder", "tenant": {"enabled": true, "description": null, "name": "tenant_name1", "id": "tenant_id1"}}, "user": {"username": "revoked_username1", "roles_links": ["role1","role2"], "id": "revoked_user_id1", "roles": [{"name": "role1"}, {"name": "role2"}], "name": "revoked_username1"}}}
02
=== added file 'examples/pki/cms/auth_token_revoked.pem'
--- examples/pki/cms/auth_token_revoked.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/auth_token_revoked.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,42 @@
1-----BEGIN CMS-----
2MIIHVgYJKoZIhvcNAQcCoIIHRzCCB0MCAQExCTAHBgUrDgMCGjCCBeQGCSqGSIb3
3DQEHAaCCBdUEggXReyJhY2Nlc3MiOiB7InNlcnZpY2VDYXRhbG9nIjogW3siZW5k
4cG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3Yx
5LzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInJlZ2lvbiI6ICJy
6ZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2
7L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInB1YmxpY1VS
8TCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThh
9NjBmY2Y4OWJiNjYxN2EifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUi
10OiAidm9sdW1lIiwgIm5hbWUiOiAidm9sdW1lIn0sIHsiZW5kcG9pbnRzIjogW3si
11YWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwgInJlZ2lvbiI6
12ICJyZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5
13MjkyL3YxIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEi
14fV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiaW1hZ2UiLCAibmFt
15ZSI6ICJnbGFuY2UifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRw
16Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5
17YmI2NjE3YSIsICJyZWdpb24iOiAicmVnaW9uT25lIiwgImludGVybmFsVVJMIjog
18Imh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYw
19ZmNmODliYjY2MTdhIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3
20NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSJ9XSwgImVu
21ZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAi
22bm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xMjcu
23MC4wLjE6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVy
24bmFsVVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsICJwdWJsaWNV
25UkwiOiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAifV0sICJlbmRwb2ludHNf
26bGlua3MiOiBbXSwgInR5cGUiOiAiaWRlbnRpdHkiLCAibmFtZSI6ICJrZXlzdG9u
27ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjAxMi0wNi0wMlQxNDo0NzozNFoi
28LCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJlbmFibGVkIjogdHJ1
29ZSwgImRlc2NyaXB0aW9uIjogbnVsbCwgIm5hbWUiOiAidGVuYW50X25hbWUxIiwg
30ImlkIjogInRlbmFudF9pZDEifX0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJyZXZv
31a2VkX3VzZXJuYW1lMSIsICJyb2xlc19saW5rcyI6IFsicm9sZTEiLCJyb2xlMiJd
32LCAiaWQiOiAicmV2b2tlZF91c2VyX2lkMSIsICJyb2xlcyI6IFt7Im5hbWUiOiAi
33cm9sZTEifSwgeyJuYW1lIjogInJvbGUyIn1dLCAibmFtZSI6ICJyZXZva2VkX3Vz
34ZXJuYW1lMSJ9fX0NCjGCAUkwggFFAgEBMIGkMIGeMQowCAYDVQQFEwE1MQswCQYD
35VQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVN1bm55dmFsZTESMBAGA1UE
36ChMJT3BlblN0YWNrMREwDwYDVQQLEwhLZXlzdG9uZTElMCMGCSqGSIb3DQEJARYW
37a2V5c3RvbmVAb3BlbnN0YWNrLm9yZzEUMBIGA1UEAxMLU2VsZiBTaWduZWQCAREw
38BwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEgYBhV5KrVjcdACPUNafkPY+lgCSlh6uc
39N55SATBcQmg1/argEUFg/cx2GcF7ftQV384iGepLEgsq+6om2wPw6DWA0RknpVLJ
40vMsHbWdGoXIZ5jRuAQTPtkXcJQOR677baDHvGJ+5zwBBDT2CmN2Tcv348+Xpjp7D
41hF/cmAXnYYo00g==
42-----END CMS-----
043
=== added file 'examples/pki/cms/auth_token_scoped.json'
--- examples/pki/cms/auth_token_scoped.json 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/auth_token_scoped.json 2012-11-30 14:11:19 +0000
@@ -0,0 +1,1 @@
1{"access": {"serviceCatalog": [{"endpoints": [{"adminURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", "region": "regionOne", "internalURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a", "publicURL": "http://127.0.0.1:8776/v1/64b6f3fbcc53435e8a60fcf89bb6617a"}], "endpoints_links": [], "type": "volume", "name": "volume"}, {"endpoints": [{"adminURL": "http://127.0.0.1:9292/v1", "region": "regionOne", "internalURL": "http://127.0.0.1:9292/v1", "publicURL": "http://127.0.0.1:9292/v1"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", "region": "regionOne", "internalURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a", "publicURL": "http://127.0.0.1:8774/v1.1/64b6f3fbcc53435e8a60fcf89bb6617a"}], "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://127.0.0.1:35357/v2.0", "region": "RegionOne", "internalURL": "http://127.0.0.1:35357/v2.0", "publicURL": "http://127.0.0.1:5000/v2.0"}], "endpoints_links": [], "type": "identity", "name": "keystone"}],"token": {"expires": "2012-06-02T14:47:34Z", "id": "placeholder", "tenant": {"enabled": true, "description": null, "name": "tenant_name1", "id": "tenant_id1"}}, "user": {"username": "user_name1", "roles_links": ["role1","role2"], "id": "user_id1", "roles": [{"name": "role1"}, {"name": "role2"}], "name": "user_name1"}}}
02
=== added file 'examples/pki/cms/auth_token_scoped.pem'
--- examples/pki/cms/auth_token_scoped.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/auth_token_scoped.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,41 @@
1-----BEGIN CMS-----
2MIIHQAYJKoZIhvcNAQcCoIIHMTCCBy0CAQExCTAHBgUrDgMCGjCCBc4GCSqGSIb3
3DQEHAaCCBb8EggW7eyJhY2Nlc3MiOiB7InNlcnZpY2VDYXRhbG9nIjogW3siZW5k
4cG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2L3Yx
5LzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInJlZ2lvbiI6ICJy
6ZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo4Nzc2
7L3YxLzY0YjZmM2ZiY2M1MzQzNWU4YTYwZmNmODliYjY2MTdhIiwgInB1YmxpY1VS
8TCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3NzYvdjEvNjRiNmYzZmJjYzUzNDM1ZThh
9NjBmY2Y4OWJiNjYxN2EifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUi
10OiAidm9sdW1lIiwgIm5hbWUiOiAidm9sdW1lIn0sIHsiZW5kcG9pbnRzIjogW3si
11YWRtaW5VUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5MjkyL3YxIiwgInJlZ2lvbiI6
12ICJyZWdpb25PbmUiLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzEyNy4wLjAuMTo5
13MjkyL3YxIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjkyOTIvdjEi
14fV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiaW1hZ2UiLCAibmFt
15ZSI6ICJnbGFuY2UifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRw
16Oi8vMTI3LjAuMC4xOjg3NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5
17YmI2NjE3YSIsICJyZWdpb24iOiAicmVnaW9uT25lIiwgImludGVybmFsVVJMIjog
18Imh0dHA6Ly8xMjcuMC4wLjE6ODc3NC92MS4xLzY0YjZmM2ZiY2M1MzQzNWU4YTYw
19ZmNmODliYjY2MTdhIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTI3LjAuMC4xOjg3
20NzQvdjEuMS82NGI2ZjNmYmNjNTM0MzVlOGE2MGZjZjg5YmI2NjE3YSJ9XSwgImVu
21ZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAi
22bm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xMjcu
23MC4wLjE6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVy
24bmFsVVJMIjogImh0dHA6Ly8xMjcuMC4wLjE6MzUzNTcvdjIuMCIsICJwdWJsaWNV
25UkwiOiAiaHR0cDovLzEyNy4wLjAuMTo1MDAwL3YyLjAifV0sICJlbmRwb2ludHNf
26bGlua3MiOiBbXSwgInR5cGUiOiAiaWRlbnRpdHkiLCAibmFtZSI6ICJrZXlzdG9u
27ZSJ9XSwidG9rZW4iOiB7ImV4cGlyZXMiOiAiMjAxMi0wNi0wMlQxNDo0NzozNFoi
28LCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJlbmFibGVkIjogdHJ1
29ZSwgImRlc2NyaXB0aW9uIjogbnVsbCwgIm5hbWUiOiAidGVuYW50X25hbWUxIiwg
30ImlkIjogInRlbmFudF9pZDEifX0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJ1c2Vy
31X25hbWUxIiwgInJvbGVzX2xpbmtzIjogWyJyb2xlMSIsInJvbGUyIl0sICJpZCI6
32ICJ1c2VyX2lkMSIsICJyb2xlcyI6IFt7Im5hbWUiOiAicm9sZTEifSwgeyJuYW1l
33IjogInJvbGUyIn1dLCAibmFtZSI6ICJ1c2VyX25hbWUxIn19fQ0KMYIBSTCCAUUC
34AQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTES
35MBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sxETAPBgNVBAsT
36CEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVuc3RhY2sub3Jn
37MRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkqhkiG9w0BAQEF
38AASBgFizBVs3dCvlHx04nUHgXHpaA9RL+e3uaaNszK9UwCBpBlv8c6+74sz6i3+G
39eYDIpL9bc6QgNJ6cKhmW5yLmS8/+mmAMAcm06bdWc7p/mqC3Ild+xmQ+OHDYyyJg
40DvtRUgtidFUCvxne/nwKK0WHJlpY+iwWqel5F+Xqmb8vheb1
41-----END CMS-----
042
=== added file 'examples/pki/cms/auth_token_unscoped.json'
--- examples/pki/cms/auth_token_unscoped.json 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/auth_token_unscoped.json 2012-11-30 14:11:19 +0000
@@ -0,0 +1,1 @@
1{"access": {"token": {"expires": "2012-08-17T15:35:34Z", "id": "01e032c996ef4406b144335915a41e79"}, "serviceCatalog": {}, "user": {"username": "user_name1", "roles_links": [], "id": "c9c89e3be3ee453fbf00c7966f6d3fbd", "roles": [{'name': 'role1'},{'name': 'role2'},], "name": "user_name1"}}}
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'examples/pki/cms/auth_token_unscoped.pem'
--- examples/pki/cms/auth_token_unscoped.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/auth_token_unscoped.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,17 @@
1-----BEGIN CMS-----
2MIICpwYJKoZIhvcNAQcCoIICmDCCApQCAQExCTAHBgUrDgMCGjCCATUGCSqGSIb3
3DQEHAaCCASYEggEieyJhY2Nlc3MiOiB7InRva2VuIjogeyJleHBpcmVzIjogIjIw
4MTItMDgtMTdUMTU6MzU6MzRaIiwgImlkIjogIjAxZTAzMmM5OTZlZjQ0MDZiMTQ0
5MzM1OTE1YTQxZTc5In0sICJzZXJ2aWNlQ2F0YWxvZyI6IHt9LCAidXNlciI6IHsi
6dXNlcm5hbWUiOiAidXNlcl9uYW1lMSIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQi
7OiAiYzljODllM2JlM2VlNDUzZmJmMDBjNzk2NmY2ZDNmYmQiLCAicm9sZXMiOiBb
8eyduYW1lJzogJ3JvbGUxJ30seyduYW1lJzogJ3JvbGUyJ30sXSwgIm5hbWUiOiAi
9dXNlcl9uYW1lMSJ9fX0xggFJMIIBRQIBATCBpDCBnjEKMAgGA1UEBRMBNTELMAkG
10A1UEBhMCVVMxCzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlTdW5ueXZhbGUxEjAQBgNV
11BAoTCU9wZW5TdGFjazERMA8GA1UECxMIS2V5c3RvbmUxJTAjBgkqhkiG9w0BCQEW
12FmtleXN0b25lQG9wZW5zdGFjay5vcmcxFDASBgNVBAMTC1NlbGYgU2lnbmVkAgER
13MAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIGAITCwkW7cAbcWbCBD5GfGMGHB9hP/
14UagaCZ8HFhlzjdQoJjvC+Mtu+3lWlwqPGR8ztY9kBc1401S2qJxD4FGo+M3CkNpF
15s0mtaT2PUJfFkDCzHqeBQNFHyZeqLjkPYnokPcw4s3i60DBGTFfAiUT3xumn8a4h
16C+zEAee35C/A+Iw=
17-----END CMS-----
018
=== added file 'examples/pki/cms/revocation_list.json'
--- examples/pki/cms/revocation_list.json 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/revocation_list.json 2012-11-30 14:11:19 +0000
@@ -0,0 +1,1 @@
1{"revoked":[{"id":"7acfcfdaf6a14aebe97c61c5947bc4d3","expires":"2012-08-14T17:58:48Z"}]}
02
=== added file 'examples/pki/cms/revocation_list.pem'
--- examples/pki/cms/revocation_list.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/cms/revocation_list.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,12 @@
1-----BEGIN CMS-----
2MIIB2QYJKoZIhvcNAQcCoIIByjCCAcYCAQExCTAHBgUrDgMCGjBpBgkqhkiG9w0B
3BwGgXARaeyJyZXZva2VkIjpbeyJpZCI6IjdhY2ZjZmRhZjZhMTRhZWJlOTdjNjFj
4NTk0N2JjNGQzIiwiZXhwaXJlcyI6IjIwMTItMDgtMTRUMTc6NTg6NDhaIn1dfQ0K
5MYIBSTCCAUUCAQEwgaQwgZ4xCjAIBgNVBAUTATUxCzAJBgNVBAYTAlVTMQswCQYD
6VQQIEwJDQTESMBAGA1UEBxMJU3Vubnl2YWxlMRIwEAYDVQQKEwlPcGVuU3RhY2sx
7ETAPBgNVBAsTCEtleXN0b25lMSUwIwYJKoZIhvcNAQkBFhZrZXlzdG9uZUBvcGVu
8c3RhY2sub3JnMRQwEgYDVQQDEwtTZWxmIFNpZ25lZAIBETAHBgUrDgMCGjANBgkq
9hkiG9w0BAQEFAASBgDNDhvViAo8EqTVVvZ00pWUWjajTwoV1w1os1XDJ1XacBUo+
10rsh7gljIIVuvHL2F9C660I5jxhb7QVsTge3CwSiDmexxBAPOs4lNR5hFH7FdT47b
11OK2qd0XnRjo5F7odUxIkozuQ/UISaNTPeWxGEMNVhpTXo2Dwn8wN1wrs/Z2E
12-----END CMS-----
013
=== added file 'examples/pki/gen_pki.sh'
--- examples/pki/gen_pki.sh 1970-01-01 00:00:00 +0000
+++ examples/pki/gen_pki.sh 2012-11-30 14:11:19 +0000
@@ -0,0 +1,222 @@
1#!/bin/bash
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17# This script generates the crypto necessary for the SSL tests.
18
19DIR=`dirname "$0"`
20CURRENT_DIR=`cd "$DIR" && pwd`
21CERTS_DIR=$CURRENT_DIR/certs
22PRIVATE_DIR=$CURRENT_DIR/private
23CMS_DIR=$CURRENT_DIR/cms
24
25
26function rm_old {
27 rm -rf $CERTS_DIR/*.pem
28 rm -rf $PRIVATE_DIR/*.pem
29}
30
31function cleanup {
32 rm -rf *.conf > /dev/null 2>&1
33 rm -rf index* > /dev/null 2>&1
34 rm -rf *.crt > /dev/null 2>&1
35 rm -rf newcerts > /dev/null 2>&1
36 rm -rf *.pem > /dev/null 2>&1
37 rm -rf serial* > /dev/null 2>&1
38}
39
40function generate_ca_conf {
41 echo '
42[ req ]
43default_bits = 1024
44default_keyfile = cakey.pem
45default_md = sha1
46
47prompt = no
48distinguished_name = ca_distinguished_name
49
50x509_extensions = ca_extensions
51
52[ ca_distinguished_name ]
53serialNumber = 5
54countryName = US
55stateOrProvinceName = CA
56localityName = Sunnyvale
57organizationName = OpenStack
58organizationalUnitName = Keystone
59emailAddress = keystone@openstack.org
60commonName = Self Signed
61
62[ ca_extensions ]
63basicConstraints = critical,CA:true
64' > ca.conf
65}
66
67function generate_ssl_req_conf {
68 echo '
69[ req ]
70default_bits = 1024
71default_keyfile = keystonekey.pem
72default_md = sha1
73
74prompt = no
75distinguished_name = distinguished_name
76
77[ distinguished_name ]
78countryName = US
79stateOrProvinceName = CA
80localityName = Sunnyvale
81organizationName = OpenStack
82organizationalUnitName = Keystone
83commonName = localhost
84emailAddress = keystone@openstack.org
85' > ssl_req.conf
86}
87
88function generate_cms_signing_req_conf {
89 echo '
90[ req ]
91default_bits = 1024
92default_keyfile = keystonekey.pem
93default_md = sha1
94
95prompt = no
96distinguished_name = distinguished_name
97
98[ distinguished_name ]
99countryName = US
100stateOrProvinceName = CA
101localityName = Sunnyvale
102organizationName = OpenStack
103organizationalUnitName = Keystone
104commonName = Keystone
105emailAddress = keystone@openstack.org
106' > cms_signing_req.conf
107}
108
109function generate_signing_conf {
110 echo '
111[ ca ]
112default_ca = signing_ca
113
114[ signing_ca ]
115dir = .
116database = $dir/index.txt
117new_certs_dir = $dir/newcerts
118
119certificate = $dir/certs/cacert.pem
120serial = $dir/serial
121private_key = $dir/private/cakey.pem
122
123default_days = 21360
124default_crl_days = 30
125default_md = sha1
126
127policy = policy_any
128
129[ policy_any ]
130countryName = supplied
131stateOrProvinceName = supplied
132localityName = optional
133organizationName = supplied
134organizationalUnitName = supplied
135emailAddress = supplied
136commonName = supplied
137' > signing.conf
138}
139
140function setup {
141 touch index.txt
142 echo '10' > serial
143 generate_ca_conf
144 mkdir newcerts
145}
146
147function check_error {
148 if [ $1 != 0 ] ; then
149 echo "Failed! rc=${1}"
150 echo 'Bailing ...'
151 cleanup
152 exit $1
153 else
154 echo 'Done'
155 fi
156}
157
158function generate_ca {
159 echo 'Generating New CA Certificate ...'
160 openssl req -x509 -newkey rsa:1024 -days 21360 -out $CERTS_DIR/cacert.pem -keyout $PRIVATE_DIR/cakey.pem -outform PEM -config ca.conf -nodes
161 check_error $?
162}
163
164function ssl_cert_req {
165 echo 'Generating SSL Certificate Request ...'
166 generate_ssl_req_conf
167 openssl req -newkey rsa:1024 -keyout $PRIVATE_DIR/ssl_key.pem -keyform PEM -out ssl_req.pem -outform PEM -config ssl_req.conf -nodes
168 check_error $?
169 #openssl req -in req.pem -text -noout
170}
171
172function cms_signing_cert_req {
173 echo 'Generating CMS Signing Certificate Request ...'
174 generate_cms_signing_req_conf
175 openssl req -newkey rsa:1024 -keyout $PRIVATE_DIR/signing_key.pem -keyform PEM -out cms_signing_req.pem -outform PEM -config cms_signing_req.conf -nodes
176 check_error $?
177 #openssl req -in req.pem -text -noout
178}
179
180function issue_certs {
181 generate_signing_conf
182 echo 'Issuing SSL Certificate ...'
183 openssl ca -in ssl_req.pem -config signing.conf -batch
184 check_error $?
185 openssl x509 -in $CURRENT_DIR/newcerts/10.pem -out $CERTS_DIR/ssl_cert.pem
186 check_error $?
187 echo 'Issuing CMS Signing Certificate ...'
188 openssl ca -in cms_signing_req.pem -config signing.conf -batch
189 check_error $?
190 openssl x509 -in $CURRENT_DIR/newcerts/11.pem -out $CERTS_DIR/signing_cert.pem
191 check_error $?
192}
193
194function create_middleware_cert {
195 cp $CERTS_DIR/ssl_cert.pem $CERTS_DIR/middleware.pem
196 cat $PRIVATE_DIR/ssl_key.pem >> $CERTS_DIR/middleware.pem
197}
198
199function check_openssl {
200 echo 'Checking openssl availability ...'
201 which openssl
202 check_error $?
203}
204
205function gen_sample_cms {
206 for json_file in "${CMS_DIR}/auth_token_revoked.json" "${CMS_DIR}/auth_token_unscoped.json" "${CMS_DIR}/auth_token_scoped.json" "${CMS_DIR}/revocation_list.json"
207 do
208 openssl cms -sign -in $json_file -nosmimecap -signer $CERTS_DIR/signing_cert.pem -inkey $PRIVATE_DIR/signing_key.pem -outform PEM -nodetach -nocerts -noattr -out ${json_file/.json/.pem}
209 done
210}
211
212check_openssl
213rm_old
214cleanup
215setup
216generate_ca
217ssl_cert_req
218cms_signing_cert_req
219issue_certs
220create_middleware_cert
221gen_sample_cms
222cleanup
0223
=== added directory 'examples/pki/private'
=== added file 'examples/pki/private/cakey.pem'
--- examples/pki/private/cakey.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/private/cakey.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,16 @@
1-----BEGIN PRIVATE KEY-----
2MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMXgnd5wlHApGxZ5
38LrpEkHU995lT9PxtMgkp0tpFhg7R5HQw9K7TfQk5NHB28hNzf8UE/c0z2pJXggP
4nAzvdx27NQeJGX5CWsi6fITZ8vH/+SxgfxxC+CE/6BkDpzw21MgBtq11vWL7XVax
5NeU12Ax889U66i3CrObuCYt2mbpzAgMBAAECgYEAligxJE9CFSrcR14Zc3zSQeqe
6fcFbpnXQveAyo2MHRTQWx2wobY19RjuI+DOn2IRSQbK2w+zrSLiMBonx3U8Kj8nx
7A4EQ75GLJEEr81TvBoIZSJAqrowNrkXNq8W++qwjlGXRjKiBAYlKMrFvR4lij4XN
86cdB7kGdSIUmhvC20sECQQD4ebCGfsgFWnrqOrco6T9eQRTvP3+gJuqYXYLuVSTC
9R4gHxT5QVXSZt/Hv3UWJ0BLDbyLzLGHf30w1AqgwsUP5AkEAy96qXq6j2+IRa5w7
102G+KZHF5N/MK/Hyy27Jw67GBVeGQj1Dwq2ZGAJBZrfXjTtQQAGdQ7EfOTCAOzHgX
112Bx0ywJAYqfGbBBIkL+VEA0SDh9WNrE2g6u9m7P371kplEGgH7dRDmzFShYz/pin
12aep8IrTHzmsBAHY9wiqh0mZkqzim2QJADTYdxkr89WfeByI1wp3f0wiDeXu3j4sp
13MBGNPcjf/8fBTXhKUGEtUiYImbxggaA+dTg8x0MT/FzreJajvO6DJwJARMc6rhzv
14aTlm4IgApcDPBeuz6SKex9TfvDUJpqACoFM4lMgyHADi9NrJBslxFHPP5eTiM2Ag
15vI7EuW837e6raQ==
16-----END PRIVATE KEY-----
017
=== added file 'examples/pki/private/signing_key.pem'
--- examples/pki/private/signing_key.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/private/signing_key.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,16 @@
1-----BEGIN PRIVATE KEY-----
2MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALqEAuiAajMQufOO
3XP2ZC7HXEG0x6iKWCRxJMBKMcnhI8IhhX4mZomfdaUhTXPTH43SZzfm3v53VUtfc
4NZ66yb1f7nVbH+iWVpEz1+R8sZ5ZcM5wh6T+4H7zGcxrKs1pUnYg+pnEWwmEV/YQ
5gmrht44QrSEiDQlWDGEBh+kEom/bAgMBAAECgYBywfSUHya4gqsW2toGQps6cauu
6s85uN0glujY0w2tO7Pnpv5errvaI12cG1BvWlAIz5MohwlfIgc919wyavCyRJgQN
7xQo5v5MEMYKKc8ppmXpRr03HLwoPLOHVs6UHRJQT9dhOBfmLzMZIP7P/lJlt2/1X
8Okwxft/PWorczKX1aQJBAORlVqP+Cj4r5kz1A77agnCvINioV1VM5n9PvzPVzYLH
95r1I53RWFooy1Hx2RUCmtSRQMZMeI9iGMg9c8d3LJ4UCQQDRDuIAd3AoNBcwXKC4
10BPNkbI9BSqnpIdZo87BzpY8rJ/ra3VHMHuq4w+gQsmmEy3pp01AZd1uBqv3s1wHy
11muffAkEAn2ZmiH+lUGy9B5q8qXfBL7naF7utb/gCqnnSvO+LxamUTSjTeKsYgg0l
12pVO503xF0fkyEDYp2FUYHQbGOwAtLQJAHkJ3N/YRx9/yU0+0+63LxQdpnNu/yDzb
13mglbywF1vZtl1fQe+NqowuGoX3JTj6McLuElQOpj1lr3siZU49bEJQJBANRazUzj
14Xfoja7wGuZ3PwHdxxoNDlJ2u0rYjcfK9VZuPGSz/25iCOkaar3OralJ3lfCWbFKA
15vvRp8Hl2Yk4hdKM=
16-----END PRIVATE KEY-----
017
=== added file 'examples/pki/private/ssl_key.pem'
--- examples/pki/private/ssl_key.pem 1970-01-01 00:00:00 +0000
+++ examples/pki/private/ssl_key.pem 2012-11-30 14:11:19 +0000
@@ -0,0 +1,16 @@
1-----BEGIN PRIVATE KEY-----
2MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALVu4bjaOH33yAx0
3WdpEqj4UDVsLxVjWxEpIbOlDlc6IfJd+cUriQtxf6ahjxtzLPERS81SnwZmrICWZ
4ngbOn733pULMTZktTJH+o7C74NdKwUSNxjlCeWUy+FqIQoje4ygoJRPpMdkp1wHN
5O0ZERwRN9e8M5TIlx/LRtk+q8bT5AgMBAAECgYAmwq6EYFJrTvE0//JmN/8qzfvg
6dI5PoWpD+F8UInUxr2T2tHOdrOLd07vGVrKYXu7cJeCIOGKa4r02azAggioL/nE9
7FgPpqEC+QROvLuhFsk1gLZ2pGQ06sveKZVMH22h59BKZkYlhjh5qd4vlmhPqkmPp
8gdXj7ZjDCJhhQdFVkQJBANp18k2mVksn8q29LMieVTSIZNN3ucDA1QHbim+3fp/O
9GxCzU7Mv1Xfnu1zoRFu5/sF3YG0Zy3TGPDrEljBC3rUCQQDUnBjVFXL35OkBZqXW
10taJPzGbsPoqAO+Ls2juS97zNzeGxUNhvcKuEvHO63PXqDxp1535DpvJEBN1rT2FF
11iaO1AkEAt/QTWWFUTqrPxY6DNFdm5fpn9E1fg7icZJkKBDJeFJCH59MpCryfovzl
12n0ERtq9ynlQ4RQYwdR8rvkylLvRP9QJAOiXHFOAc5XeR0nREfwiGL9TzgUFJl/DJ
13C4ZULMnctVzNkTVPPItQHal87WppR26CCiUZ/161e6zo8eRv8hjG0QJABWqfYQuK
14dWH8nxlXS+NFUDbsCdL+XpOVE7iEH7hvSw/A/kz40mLx8sDp/Fz1ysrogR/L+NGC
15Vrlwm4q/WYJO0Q==
16-----END PRIVATE KEY-----
017
=== added file 'keystoneclient/access.py'
--- keystoneclient/access.py 1970-01-01 00:00:00 +0000
+++ keystoneclient/access.py 2012-11-30 14:11:19 +0000
@@ -0,0 +1,144 @@
1# Copyright 2012 Nebula, Inc.
2#
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17
18class AccessInfo(dict):
19 """An object for encapsulating a raw authentication token from keystone
20 and helper methods for extracting useful values from that token."""
21
22 def __init__(self, *args, **kwargs):
23 dict.__init__(self, *args, **kwargs)
24
25 @property
26 def auth_token(self):
27 """ Returns the token_id associated with the auth request, to be used
28 in headers for authenticating OpenStack API requests.
29
30 :returns: str
31 """
32 return self['token'].get('id', None)
33
34 @property
35 def username(self):
36 """ Returns the username associated with the authentication request.
37 Follows the pattern defined in the V2 API of first looking for 'name',
38 returning that if available, and falling back to 'username' if name
39 is unavailable.
40
41 :returns: str
42 """
43 name = self['user'].get('name', None)
44 if name:
45 return name
46 else:
47 return self['user'].get('username', None)
48
49 @property
50 def user_id(self):
51 """ Returns the user id associated with the authentication request.
52
53 :returns: str
54 """
55 return self['user'].get('id', None)
56
57 @property
58 def tenant_name(self):
59 """ Returns the tenant (project) name associated with the
60 authentication request.
61
62 :returns: str
63 """
64 tenant_dict = self['token'].get('tenant', None)
65 if tenant_dict:
66 return tenant_dict.get('name', None)
67 return None
68
69 @property
70 def project_name(self):
71 """ Synonym for tenant_name """
72 return self.tenant_name
73
74 @property
75 def scoped(self):
76 """ Returns true if the authorization token was scoped to a tenant
77 (project), and contains a populated service catalog.
78
79 :returns: bool
80 """
81 if ('serviceCatalog' in self
82 and self['serviceCatalog']
83 and 'tenant' in self['token']):
84 return True
85 return False
86
87 @property
88 def tenant_id(self):
89 """ Returns the tenant (project) id associated with the authentication
90 request, or None if the authentication request wasn't scoped to a
91 tenant (project).
92
93 :returns: str
94 """
95 tenant_dict = self['token'].get('tenant', None)
96 if tenant_dict:
97 return tenant_dict.get('id', None)
98 return None
99
100 @property
101 def project_id(self):
102 """ Synonym for project_id """
103 return self.tenant_id
104
105 @property
106 def auth_url(self):
107 """ Returns a tuple of URLs from publicURL and adminURL for the service
108 'identity' from the service catalog associated with the authorization
109 request. If the authentication request wasn't scoped to a tenant
110 (project), this property will return None.
111
112 :returns: tuple of urls
113 """
114 return_list = []
115 if 'serviceCatalog' in self and self['serviceCatalog']:
116 identity_services = [x for x in self['serviceCatalog']
117 if x['type'] == 'identity']
118 for svc in identity_services:
119 for endpoint in svc['endpoints']:
120 if 'publicURL' in endpoint:
121 return_list.append(endpoint['publicURL'])
122 if len(return_list) > 0:
123 return tuple(return_list)
124 return None
125
126 @property
127 def management_url(self):
128 """ Returns the first adminURL for 'identity' from the service catalog
129 associated with the authorization request, or None if the
130 authentication request wasn't scoped to a tenant (project).
131
132 :returns: tuple of urls
133 """
134 return_list = []
135 if 'serviceCatalog' in self and self['serviceCatalog']:
136 identity_services = [x for x in self['serviceCatalog']
137 if x['type'] == 'identity']
138 for svc in identity_services:
139 for endpoint in svc['endpoints']:
140 if 'adminURL' in endpoint:
141 return_list.append(endpoint['adminURL'])
142 if len(return_list) > 0:
143 return tuple(return_list)
144 return None
0145
=== modified file 'keystoneclient/base.py'
--- keystoneclient/base.py 2012-06-22 12:58:18 +0000
+++ keystoneclient/base.py 2012-11-30 14:11:19 +0000
@@ -18,6 +18,8 @@
18Base utilities to build API operation managers and objects on top of.18Base utilities to build API operation managers and objects on top of.
19"""19"""
2020
21import urllib
22
21from keystoneclient import exceptions23from keystoneclient import exceptions
2224
2325
@@ -76,7 +78,11 @@
7678
77 def _get(self, url, response_key):79 def _get(self, url, response_key):
78 resp, body = self.api.get(url)80 resp, body = self.api.get(url)
79 return self.resource_class(self, body[response_key])81 return self.resource_class(self, body[response_key], loaded=True)
82
83 def _head(self, url):
84 resp, body = self.api.head(url)
85 return resp.status == 204
8086
81 def _create(self, url, body, response_key, return_raw=False):87 def _create(self, url, body, response_key, return_raw=False):
82 resp, body = self.api.post(url, body=body)88 resp, body = self.api.post(url, body=body)
@@ -87,11 +93,15 @@
87 def _delete(self, url):93 def _delete(self, url):
88 resp, body = self.api.delete(url)94 resp, body = self.api.delete(url)
8995
90 def _update(self, url, body, response_key=None, method="PUT"):96 def _update(self, url, body=None, response_key=None, method="PUT"):
91 methods = {"PUT": self.api.put,97 methods = {"PUT": self.api.put,
92 "POST": self.api.post}98 "POST": self.api.post,
99 "PATCH": self.api.patch}
93 try:100 try:
94 resp, body = methods[method](url, body=body)101 if body is not None:
102 resp, body = methods[method](url, body=body)
103 else:
104 resp, body = methods[method](url)
95 except KeyError:105 except KeyError:
96 raise exceptions.ClientException("Invalid update method: %s"106 raise exceptions.ClientException("Invalid update method: %s"
97 % method)107 % method)
@@ -139,6 +149,115 @@
139 return found149 return found
140150
141151
152class CrudManager(Manager):
153 """Base manager class for manipulating Keystone entities.
154
155 Children of this class are expected to define a `collection_key` and `key`.
156
157 - `collection_key`: Usually a plural noun by convention (e.g. `entities`);
158 used to refer collections in both URL's (e.g. `/v3/entities`) and JSON
159 objects containing a list of member resources (e.g. `{'entities': [{},
160 {}, {}]}`).
161 - `key`: Usually a singular noun by convention (e.g. `entity`); used to
162 refer to an individual member of the collection.
163
164 """
165 collection_key = None
166 key = None
167
168 def build_url(self, base_url=None, **kwargs):
169 """Builds a resource URL for the given kwargs.
170
171 Given an example collection where `collection_key = 'entities'` and
172 `key = 'entity'`, the following URL's could be generated.
173
174 By default, the URL will represent a collection of entities, e.g.::
175
176 /entities
177
178 If kwargs contains an `entity_id`, then the URL will represent a
179 specific member, e.g.::
180
181 /entities/{entity_id}
182
183 If a `base_url` is provided, the generated URL will be appended to it.
184
185 """
186 url = base_url if base_url is not None else ''
187
188 url += '/%s' % self.collection_key
189
190 # do we have a specific entity?
191 entity_id = kwargs.get('%s_id' % self.key)
192 if entity_id is not None:
193 url += '/%s' % entity_id
194
195 return url
196
197 def _filter_kwargs(self, kwargs):
198 # drop null values
199 for key, ref in kwargs.copy().iteritems():
200 if ref is None:
201 kwargs.pop(key)
202 else:
203 id_value = getid(ref)
204 if id_value != ref:
205 kwargs.pop(key)
206 kwargs['%s_id' % key] = id_value
207 return kwargs
208
209 def create(self, **kwargs):
210 kwargs = self._filter_kwargs(kwargs)
211 return self._create(
212 self.build_url(**kwargs),
213 {self.key: kwargs},
214 self.key)
215
216 def get(self, **kwargs):
217 kwargs = self._filter_kwargs(kwargs)
218 return self._get(
219 self.build_url(**kwargs),
220 self.key)
221
222 def head(self, **kwargs):
223 kwargs = self._filter_kwargs(kwargs)
224 return self._head(self.build_url(**kwargs))
225
226 def list(self, base_url=None, **kwargs):
227 kwargs = self._filter_kwargs(kwargs)
228
229 return self._list(
230 '%(base_url)s%(query)s' % {
231 'base_url': self.build_url(base_url=base_url, **kwargs),
232 'query': '?%s' % urllib.urlencode(kwargs) if kwargs else '',
233 },
234 self.collection_key)
235
236 def put(self, base_url=None, **kwargs):
237 kwargs = self._filter_kwargs(kwargs)
238
239 return self._update(
240 self.build_url(base_url=base_url, **kwargs),
241 method='PUT')
242
243 def update(self, **kwargs):
244 kwargs = self._filter_kwargs(kwargs)
245 params = kwargs.copy()
246 params.pop('%s_id' % self.key)
247
248 return self._update(
249 self.build_url(**kwargs),
250 {self.key: params},
251 self.key,
252 method='PATCH')
253
254 def delete(self, **kwargs):
255 kwargs = self._filter_kwargs(kwargs)
256
257 return self._delete(
258 self.build_url(**kwargs))
259
260
142class Resource(object):261class Resource(object):
143 """262 """
144 A resource represents a particular instance of an object (tenant, user,263 A resource represents a particular instance of an object (tenant, user,
@@ -185,6 +304,9 @@
185 if new:304 if new:
186 self._add_details(new._info)305 self._add_details(new._info)
187306
307 def delete(self):
308 return self.manager.delete(self)
309
188 def __eq__(self, other):310 def __eq__(self, other):
189 if not isinstance(other, self.__class__):311 if not isinstance(other, self.__class__):
190 return False312 return False
191313
=== modified file 'keystoneclient/client.py'
--- keystoneclient/client.py 2012-09-07 13:13:18 +0000
+++ keystoneclient/client.py 2012-11-30 14:11:19 +0000
@@ -10,7 +10,6 @@
1010
11import copy11import copy
12import logging12import logging
13import os
14import urlparse13import urlparse
1514
16import httplib215import httplib2
@@ -26,6 +25,7 @@
26 urlparse.parse_qsl = cgi.parse_qsl25 urlparse.parse_qsl = cgi.parse_qsl
2726
2827
28from keystoneclient import access
29from keystoneclient import exceptions29from keystoneclient import exceptions
3030
3131
@@ -39,40 +39,71 @@
39 def __init__(self, username=None, tenant_id=None, tenant_name=None,39 def __init__(self, username=None, tenant_id=None, tenant_name=None,
40 password=None, auth_url=None, region_name=None, timeout=None,40 password=None, auth_url=None, region_name=None, timeout=None,
41 endpoint=None, token=None, cacert=None, key=None,41 endpoint=None, token=None, cacert=None, key=None,
42 cert=None, insecure=False):42 cert=None, insecure=False, original_ip=None, debug=False,
43 auth_ref=None):
43 super(HTTPClient, self).__init__(timeout=timeout, ca_certs=cacert)44 super(HTTPClient, self).__init__(timeout=timeout, ca_certs=cacert)
44 if cert:45 if cert:
45 if key:46 if key:
46 self.add_certificate(key=key, cert=cert, domain='')47 self.add_certificate(key=key, cert=cert, domain='')
47 else:48 else:
48 self.add_certificate(key=cert, cert=cert, domain='')49 self.add_certificate(key=cert, cert=cert, domain='')
49 self.username = username50 self.version = 'v2.0'
50 self.tenant_id = tenant_id51 # set baseline defaults
51 self.tenant_name = tenant_name52 self.username = None
53 self.tenant_id = None
54 self.tenant_name = None
55 self.auth_url = None
56 self.token = None
57 self.auth_token = None
58 self.management_url = None
59 # if loading from a dictionary passed in via auth_ref,
60 # load values from AccessInfo parsing that dictionary
61 self.auth_ref = access.AccessInfo(**auth_ref) if auth_ref else None
62 if self.auth_ref:
63 self.username = self.auth_ref.username
64 self.tenant_id = self.auth_ref.tenant_id
65 self.tenant_name = self.auth_ref.tenant_name
66 self.auth_url = self.auth_ref.auth_url[0]
67 self.management_url = self.auth_ref.management_url[0]
68 self.auth_token = self.auth_ref.auth_token
69 # allow override of the auth_ref defaults from explicit
70 # values provided to the client
71 if username:
72 self.username = username
73 if tenant_id:
74 self.tenant_id = tenant_id
75 if tenant_name:
76 self.tenant_name = tenant_name
77 if auth_url:
78 self.auth_url = auth_url.rstrip('/')
79 if token:
80 self.auth_token = token
81 if endpoint:
82 self.management_url = endpoint.rstrip('/')
52 self.password = password83 self.password = password
53 self.auth_url = auth_url.rstrip('/') if auth_url else None84 self.original_ip = original_ip
54 self.version = 'v2.0'
55 self.region_name = region_name85 self.region_name = region_name
56 self.auth_token = token
57
58 self.management_url = endpoint
5986
60 # httplib2 overrides87 # httplib2 overrides
61 self.force_exception_to_status_code = True88 self.force_exception_to_status_code = True
62 self.disable_ssl_certificate_validation = insecure89 self.disable_ssl_certificate_validation = insecure
6390
64 # logging setup91 # logging setup
65 self.debug_log = os.environ.get('KEYSTONECLIENT_DEBUG', False)92 self.debug_log = debug
66 if self.debug_log:93 if self.debug_log:
67 ch = logging.StreamHandler()94 ch = logging.StreamHandler()
68 _logger.setLevel(logging.DEBUG)95 _logger.setLevel(logging.DEBUG)
69 _logger.addHandler(ch)96 _logger.addHandler(ch)
7097
71 def authenticate(self):98 def authenticate(self):
72 """ Authenticate against the keystone API.99 """ Authenticate against the Identity API.
73100
74 Not implemented here because auth protocols should be API101 Not implemented here because auth protocols should be API
75 version-specific.102 version-specific.
103
104 Expected to authenticate or validate an existing authentication
105 reference already associated with the client. Invoking this call
106 *always* makes a call to the Keystone.
76 """107 """
77 raise NotImplementedError108 raise NotImplementedError
78109
@@ -107,6 +138,9 @@
107 if self.debug_log:138 if self.debug_log:
108 _logger.debug("RESP: %s\nRESP BODY: %s\n", resp, body)139 _logger.debug("RESP: %s\nRESP BODY: %s\n", resp, body)
109140
141 def serialize(self, entity):
142 return json.dumps(entity)
143
110 def request(self, url, method, **kwargs):144 def request(self, url, method, **kwargs):
111 """ Send an http request with the specified characteristics.145 """ Send an http request with the specified characteristics.
112146
@@ -117,9 +151,12 @@
117 request_kwargs = copy.copy(kwargs)151 request_kwargs = copy.copy(kwargs)
118 request_kwargs.setdefault('headers', kwargs.get('headers', {}))152 request_kwargs.setdefault('headers', kwargs.get('headers', {}))
119 request_kwargs['headers']['User-Agent'] = self.USER_AGENT153 request_kwargs['headers']['User-Agent'] = self.USER_AGENT
154 if self.original_ip:
155 request_kwargs['headers']['Forwarded'] = "for=%s;by=%s" % (
156 self.original_ip, self.USER_AGENT)
120 if 'body' in kwargs:157 if 'body' in kwargs:
121 request_kwargs['headers']['Content-Type'] = 'application/json'158 request_kwargs['headers']['Content-Type'] = 'application/json'
122 request_kwargs['body'] = json.dumps(kwargs['body'])159 request_kwargs['body'] = self.serialize(kwargs['body'])
123160
124 self.http_log_req((url, method,), request_kwargs)161 self.http_log_req((url, method,), request_kwargs)
125 resp, body = super(HTTPClient, self).request(url,162 resp, body = super(HTTPClient, self).request(url,
@@ -127,6 +164,13 @@
127 **request_kwargs)164 **request_kwargs)
128 self.http_log_resp(resp, body)165 self.http_log_resp(resp, body)
129166
167 if resp.status in (400, 401, 403, 404, 408, 409, 413, 500, 501):
168 _logger.debug("Request returned failure status: %s", resp.status)
169 raise exceptions.from_response(resp, body)
170 elif resp.status in (301, 302, 305):
171 # Redirected. Reissue the request to the new location.
172 return self.request(resp['location'], method, **kwargs)
173
130 if body:174 if body:
131 try:175 try:
132 body = json.loads(body)176 body = json.loads(body)
@@ -136,51 +180,38 @@
136 _logger.debug("No body was returned.")180 _logger.debug("No body was returned.")
137 body = None181 body = None
138182
139 if resp.status in (400, 401, 403, 404, 408, 409, 413, 500, 501):
140 _logger.exception("Request returned failure status.")
141 raise exceptions.from_response(resp, body)
142 elif resp.status in (301, 302, 305):
143 # Redirected. Reissue the request to the new location.
144 return self.request(resp['location'], method, **kwargs)
145
146 return resp, body183 return resp, body
147184
148 def _cs_request(self, url, method, **kwargs):185 def _cs_request(self, url, method, **kwargs):
149 if not self.management_url:186 """ Makes an authenticated request to keystone endpoint by
150 self.authenticate()187 concatenating self.management_url and url and passing in method and
188 any associated kwargs. """
151189
190 if self.management_url is None:
191 raise exceptions.AuthorizationFailure(
192 'Current authorization does not have a known management url')
152 kwargs.setdefault('headers', {})193 kwargs.setdefault('headers', {})
153 if self.auth_token:194 if self.auth_token:
154 kwargs['headers']['X-Auth-Token'] = self.auth_token195 kwargs['headers']['X-Auth-Token'] = self.auth_token
155196
156 # Perform the request once. If we get a 401 back then it197 resp, body = self.request(self.management_url + url, method,
157 # might be because the auth token expired, so try to198 **kwargs)
158 # re-authenticate and try again. If it still fails, bail.199 return resp, body
159 try:
160 resp, body = self.request(self.management_url + url, method,
161 **kwargs)
162 return resp, body
163 except exceptions.Unauthorized:
164 try:
165 if getattr(self, '_failures', 0) < 1:
166 self._failures = getattr(self, '_failures', 0) + 1
167 self.authenticate()
168 resp, body = self.request(self.management_url + url,
169 method, **kwargs)
170 return resp, body
171 else:
172 raise
173 except exceptions.Unauthorized:
174 raise
175200
176 def get(self, url, **kwargs):201 def get(self, url, **kwargs):
177 return self._cs_request(url, 'GET', **kwargs)202 return self._cs_request(url, 'GET', **kwargs)
178203
204 def head(self, url, **kwargs):
205 return self._cs_request(url, 'HEAD', **kwargs)
206
179 def post(self, url, **kwargs):207 def post(self, url, **kwargs):
180 return self._cs_request(url, 'POST', **kwargs)208 return self._cs_request(url, 'POST', **kwargs)
181209
182 def put(self, url, **kwargs):210 def put(self, url, **kwargs):
183 return self._cs_request(url, 'PUT', **kwargs)211 return self._cs_request(url, 'PUT', **kwargs)
184212
213 def patch(self, url, **kwargs):
214 return self._cs_request(url, 'PATCH', **kwargs)
215
185 def delete(self, url, **kwargs):216 def delete(self, url, **kwargs):
186 return self._cs_request(url, 'DELETE', **kwargs)217 return self._cs_request(url, 'DELETE', **kwargs)
187218
=== added directory 'keystoneclient/common'
=== added file 'keystoneclient/common/__init__.py'
=== added file 'keystoneclient/common/cms.py'
--- keystoneclient/common/cms.py 1970-01-01 00:00:00 +0000
+++ keystoneclient/common/cms.py 2012-11-30 14:11:19 +0000
@@ -0,0 +1,169 @@
1import hashlib
2
3import logging
4
5
6subprocess = None
7LOG = logging.getLogger(__name__)
8PKI_ANS1_PREFIX = 'MII'
9
10
11def _ensure_subprocess():
12 # NOTE(vish): late loading subprocess so we can
13 # use the green version if we are in
14 # eventlet.
15 global subprocess
16 if not subprocess:
17 try:
18 from eventlet import patcher
19 if patcher.already_patched.get('os'):
20 from eventlet.green import subprocess
21 else:
22 import subprocess
23 except ImportError:
24 import subprocess
25
26
27def cms_verify(formatted, signing_cert_file_name, ca_file_name):
28 """
29 verifies the signature of the contents IAW CMS syntax
30 """
31 _ensure_subprocess()
32 process = subprocess.Popen(["openssl", "cms", "-verify",
33 "-certfile", signing_cert_file_name,
34 "-CAfile", ca_file_name,
35 "-inform", "PEM",
36 "-nosmimecap", "-nodetach",
37 "-nocerts", "-noattr"],
38 stdin=subprocess.PIPE,
39 stdout=subprocess.PIPE,
40 stderr=subprocess.PIPE)
41 output, err = process.communicate(formatted)
42 retcode = process.poll()
43 if retcode:
44 LOG.error('Verify error: %s' % err)
45 raise subprocess.CalledProcessError(retcode, "openssl", output=err)
46 return output
47
48
49def token_to_cms(signed_text):
50 copy_of_text = signed_text.replace('-', '/')
51
52 formatted = "-----BEGIN CMS-----\n"
53 line_length = 64
54 while len(copy_of_text) > 0:
55 if (len(copy_of_text) > line_length):
56 formatted += copy_of_text[:line_length]
57 copy_of_text = copy_of_text[line_length:]
58 else:
59 formatted += copy_of_text
60 copy_of_text = ""
61 formatted += "\n"
62
63 formatted += "-----END CMS-----\n"
64
65 return formatted
66
67
68def verify_token(token, signing_cert_file_name, ca_file_name):
69 return cms_verify(token_to_cms(token),
70 signing_cert_file_name,
71 ca_file_name)
72
73
74def is_ans1_token(token):
75 '''
76 thx to ayoung for sorting this out.
77
78 base64 decoded hex representation of MII is 3082
79 In [3]: binascii.hexlify(base64.b64decode('MII='))
80 Out[3]: '3082'
81
82 re: http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
83
84 pg4: For tags from 0 to 30 the first octet is the identfier
85 pg10: Hex 30 means sequence, followed by the length of that sequence.
86 pg5: Second octet is the length octet
87 first bit indicates short or long form, next 7 bits encode the number
88 of subsequent octets that make up the content length octets as an
89 unsigned binary int
90
91 82 = 10000010 (first bit indicates long form)
92 0000010 = 2 octets of content length
93 so read the next 2 octets to get the length of the content.
94
95 In the case of a very large content length there could be a requirement to
96 have more than 2 octets to designate the content length, therefore
97 requiring us to check for MIM, MIQ, etc.
98 In [4]: base64.b64encode(binascii.a2b_hex('3083'))
99 Out[4]: 'MIM='
100 In [5]: base64.b64encode(binascii.a2b_hex('3084'))
101 Out[5]: 'MIQ='
102 Checking for MI would become invalid at 16 octets of content length
103 10010000 = 90
104 In [6]: base64.b64encode(binascii.a2b_hex('3090'))
105 Out[6]: 'MJA='
106 Checking for just M is insufficient
107
108 But we will only check for MII:
109 Max length of the content using 2 octets is 7FFF or 32767
110 It's not practical to support a token of this length or greater in http
111 therefore, we will check for MII only and ignore the case of larger tokens
112 '''
113 return token[:3] == PKI_ANS1_PREFIX
114
115
116def cms_sign_text(text, signing_cert_file_name, signing_key_file_name):
117 """ Uses OpenSSL to sign a document
118 Produces a Base64 encoding of a DER formatted CMS Document
119 http://en.wikipedia.org/wiki/Cryptographic_Message_Syntax
120 """
121 _ensure_subprocess()
122 process = subprocess.Popen(["openssl", "cms", "-sign",
123 "-signer", signing_cert_file_name,
124 "-inkey", signing_key_file_name,
125 "-outform", "PEM",
126 "-nosmimecap", "-nodetach",
127 "-nocerts", "-noattr"],
128 stdin=subprocess.PIPE,
129 stdout=subprocess.PIPE,
130 stderr=subprocess.PIPE)
131 output, err = process.communicate(text)
132 retcode = process.poll()
133 if retcode or "Error" in err:
134 LOG.error('Signing error: %s' % err)
135 raise subprocess.CalledProcessError(retcode, "openssl")
136 return output
137
138
139def cms_sign_token(text, signing_cert_file_name, signing_key_file_name):
140 output = cms_sign_text(text, signing_cert_file_name, signing_key_file_name)
141 return cms_to_token(output)
142
143
144def cms_to_token(cms_text):
145
146 start_delim = "-----BEGIN CMS-----"
147 end_delim = "-----END CMS-----"
148 signed_text = cms_text
149 signed_text = signed_text.replace('/', '-')
150 signed_text = signed_text.replace(start_delim, '')
151 signed_text = signed_text.replace(end_delim, '')
152 signed_text = signed_text.replace('\n', '')
153
154 return signed_text
155
156
157def cms_hash_token(token_id):
158 """
159 return: for ans1_token, returns the hash of the passed in token
160 otherwise, returns what it was passed in.
161 """
162 if token_id is None:
163 return None
164 if is_ans1_token(token_id):
165 hasher = hashlib.md5()
166 hasher.update(token_id)
167 return hasher.hexdigest()
168 else:
169 return token_id
0170
=== added directory 'keystoneclient/contrib'
=== added file 'keystoneclient/contrib/__init__.py'
=== added directory 'keystoneclient/contrib/bootstrap'
=== added file 'keystoneclient/contrib/bootstrap/__init__.py'
=== added file 'keystoneclient/contrib/bootstrap/shell.py'
--- keystoneclient/contrib/bootstrap/shell.py 1970-01-01 00:00:00 +0000
+++ keystoneclient/contrib/bootstrap/shell.py 2012-11-30 14:11:19 +0000
@@ -0,0 +1,28 @@
1from keystoneclient import utils
2from keystoneclient.v2_0 import client
3
4
5@utils.arg('--user-name', metavar='<user-name>', default='admin', dest='user',
6 help='The name of the user to be created (default="admin").')
7@utils.arg('--pass', metavar='<password>', required=True, dest='passwd',
8 help='The password for the new user.')
9@utils.arg('--role-name', metavar='<role-name>', default='admin', dest='role',
10 help='The name of the role to be created and granted to the user '
11 '(default="admin").')
12@utils.arg('--tenant-name', metavar='<tenant-name>', default='admin',
13 dest='tenant',
14 help='The name of the tenant to be created (default="admin").')
15def do_bootstrap(kc, args):
16 """Grants a new role to a new user on a new tenant, after creating each."""
17 tenant = kc.tenants.create(tenant_name=args.tenant)
18 role = kc.roles.create(name=args.role)
19 user = kc.users.create(name=args.user, password=args.passwd, email=None)
20 kc.roles.add_user_role(user=user, role=role, tenant=tenant)
21
22 # verify the result
23 user_client = client.Client(
24 username=args.user,
25 password=args.passwd,
26 tenant_name=args.tenant,
27 auth_url=kc.management_url)
28 user_client.authenticate()
029
=== modified file 'keystoneclient/exceptions.py'
--- keystoneclient/exceptions.py 2012-06-22 12:58:18 +0000
+++ keystoneclient/exceptions.py 2012-11-30 14:11:19 +0000
@@ -9,6 +9,10 @@
9 pass9 pass
1010
1111
12class ValidationError(Exception):
13 pass
14
15
12class AuthorizationFailure(Exception):16class AuthorizationFailure(Exception):
13 pass17 pass
1418
@@ -24,6 +28,11 @@
24 pass28 pass
2529
2630
31class EmptyCatalog(Exception):
32 """ The service catalog is empty. """
33 pass
34
35
27class ClientException(Exception):36class ClientException(Exception):
28 """37 """
29 The base exception class for all exceptions this library raises.38 The base exception class for all exceptions this library raises.
@@ -95,6 +104,14 @@
95 message = "Not Implemented"104 message = "Not Implemented"
96105
97106
107class ServiceUnavailable(ClientException):
108 """
109 HTTP 503 - Service Unavailable: The server is currently unavailable.
110 """
111 http_status = 503
112 message = "Service Unavailable"
113
114
98# In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()115# In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()
99# so we can do this:116# so we can do this:
100# _code_map = dict((c.http_status, c)117# _code_map = dict((c.http_status, c)
@@ -106,7 +123,8 @@
106 Forbidden,123 Forbidden,
107 NotFound,124 NotFound,
108 OverLimit,125 OverLimit,
109 HTTPNotImplemented])126 HTTPNotImplemented,
127 ServiceUnavailable])
110128
111129
112def from_response(response, body):130def from_response(response, body):
113131
=== modified file 'keystoneclient/generic/shell.py'
--- keystoneclient/generic/shell.py 2012-03-26 14:01:05 +0000
+++ keystoneclient/generic/shell.py 2012-11-30 14:11:19 +0000
@@ -28,13 +28,15 @@
28 extensions supported.28 extensions supported.
2929
30 Usage::30 Usage::
31 $ keystone discover31
32 Keystone found at http://localhost:3535732 $ keystone discover
33 - supports version v1.0 (DEPRECATED) here http://localhost:35357/v1.033 Keystone found at http://localhost:35357
34 - supports version v1.1 (CURRENT) here http://localhost:35357/v1.134
35 - supports version v2.0 (BETA) here http://localhost:35357/v2.035 - supports version v1.0 (DEPRECATED) here http://localhost:35357/v1.0
36 - and RAX-KSKEY: Rackspace API Key Authentication Admin Extension36 - supports version v1.1 (CURRENT) here http://localhost:35357/v1.1
37 - and RAX-KSGRP: Rackspace Keystone Group Extensions37 - supports version v2.0 (CURRENT) here http://localhost:35357/v2.0
38 - and RAX-KSKEY: Rackspace API Key Authentication Admin Extension
39 - and RAX-KSGRP: Rackspace Keystone Group Extensions
38 """40 """
39 if cs.endpoint:41 if cs.endpoint:
40 versions = cs.discover(cs.endpoint)42 versions = cs.discover(cs.endpoint)
4143
=== added directory 'keystoneclient/locale'
=== added file 'keystoneclient/locale/keystoneclient.pot'
--- keystoneclient/locale/keystoneclient.pot 1970-01-01 00:00:00 +0000
+++ keystoneclient/locale/keystoneclient.pot 2012-11-30 14:11:19 +0000
@@ -0,0 +1,20 @@
1# Translations template for python-keystoneclient.
2# Copyright (C) 2012 ORGANIZATION
3# This file is distributed under the same license as the
4# python-keystoneclient project.
5# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
6#
7#, fuzzy
8msgid ""
9msgstr ""
10"Project-Id-Version: python-keystoneclient 0.1.3.12\n"
11"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
12"POT-Creation-Date: 2012-09-29 16:02-0700\n"
13"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15"Language-Team: LANGUAGE <LL@li.org>\n"
16"MIME-Version: 1.0\n"
17"Content-Type: text/plain; charset=utf-8\n"
18"Content-Transfer-Encoding: 8bit\n"
19"Generated-By: Babel 0.9.6\n"
20
021
=== added directory 'keystoneclient/middleware'
=== added file 'keystoneclient/middleware/__init__.py'
=== added file 'keystoneclient/middleware/auth_token.py'
--- keystoneclient/middleware/auth_token.py 1970-01-01 00:00:00 +0000
+++ keystoneclient/middleware/auth_token.py 2012-11-30 14:11:19 +0000
@@ -0,0 +1,864 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010-2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14# implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18"""
19TOKEN-BASED AUTH MIDDLEWARE
20
21This WSGI component:
22
23* Verifies that incoming client requests have valid tokens by validating
24 tokens with the auth service.
25* Rejects unauthenticated requests UNLESS it is in 'delay_auth_decision'
26 mode, which means the final decision is delegated to the downstream WSGI
27 component (usually the OpenStack service)
28* Collects and forwards identity information based on a valid token
29 such as user name, tenant, etc
30
31Refer to: http://keystone.openstack.org/middlewarearchitecture.html
32
33HEADERS
34-------
35
36* Headers starting with HTTP\_ is a standard http header
37* Headers starting with HTTP_X is an extended http header
38
39Coming in from initial call from client or customer
40^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
41
42HTTP_X_AUTH_TOKEN
43 The client token being passed in.
44
45HTTP_X_STORAGE_TOKEN
46 The client token being passed in (legacy Rackspace use) to support
47 swift/cloud files
48
49Used for communication between components
50^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
51
52WWW-Authenticate
53 HTTP header returned to a user indicating which endpoint to use
54 to retrieve a new token
55
56What we add to the request for use by the OpenStack service
57^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
58
59HTTP_X_IDENTITY_STATUS
60 'Confirmed' or 'Invalid'
61 The underlying service will only see a value of 'Invalid' if the Middleware
62 is configured to run in 'delay_auth_decision' mode
63
64HTTP_X_TENANT_ID
65 Identity service managed unique identifier, string
66
67HTTP_X_TENANT_NAME
68 Unique tenant identifier, string
69
70HTTP_X_USER_ID
71 Identity-service managed unique identifier, string
72
73HTTP_X_USER_NAME
74 Unique user identifier, string
75
76HTTP_X_ROLES
77 Comma delimited list of case-sensitive Roles
78
79HTTP_X_SERVICE_CATALOG
80 json encoded keystone service catalog (optional).
81
82HTTP_X_TENANT
83 *Deprecated* in favor of HTTP_X_TENANT_ID and HTTP_X_TENANT_NAME
84 Keystone-assigned unique identifier, deprecated
85
86HTTP_X_USER
87 *Deprecated* in favor of HTTP_X_USER_ID and HTTP_X_USER_NAME
88 Unique user name, string
89
90HTTP_X_ROLE
91 *Deprecated* in favor of HTTP_X_ROLES
92 This is being renamed, and the new header contains the same data.
93
94OTHER ENVIRONMENT VARIABLES
95---------------------------
96
97keystone.token_info
98 Information about the token discovered in the process of
99 validation. This may include extended information returned by the
100 Keystone token validation call, as well as basic information about
101 the tenant and user.
102
103"""
104
105import datetime
106import httplib
107import json
108import logging
109import os
110import stat
111import time
112import webob
113import webob.exc
114
115from keystoneclient.openstack.common import jsonutils
116from keystoneclient.common import cms
117from keystoneclient import utils
118from keystoneclient.openstack.common import timeutils
119
120CONF = None
121try:
122 from openstack.common import cfg
123 CONF = cfg.CONF
124except ImportError:
125 # cfg is not a library yet, try application copies
126 for app in 'nova', 'glance', 'quantum', 'cinder':
127 try:
128 cfg = __import__('%s.openstack.common.cfg' % app,
129 fromlist=['%s.openstack.common' % app])
130 # test which application middleware is running in
131 if hasattr(cfg, 'CONF') and 'config_file' in cfg.CONF:
132 CONF = cfg.CONF
133 break
134 except ImportError:
135 pass
136if not CONF:
137 from keystoneclient.openstack.common import cfg
138 CONF = cfg.CONF
139LOG = logging.getLogger(__name__)
140
141# alternative middleware configuration in the main application's
142# configuration file e.g. in nova.conf
143# [keystone_authtoken]
144# auth_host = 127.0.0.1
145# auth_port = 35357
146# auth_protocol = http
147# admin_tenant_name = admin
148# admin_user = admin
149# admin_password = badpassword
150opts = [
151 cfg.StrOpt('auth_admin_prefix', default=''),
152 cfg.StrOpt('auth_host', default='127.0.0.1'),
153 cfg.IntOpt('auth_port', default=35357),
154 cfg.StrOpt('auth_protocol', default='https'),
155 cfg.StrOpt('auth_uri', default=None),
156 cfg.BoolOpt('delay_auth_decision', default=False),
157 cfg.StrOpt('admin_token'),
158 cfg.StrOpt('admin_user'),
159 cfg.StrOpt('admin_password'),
160 cfg.StrOpt('admin_tenant_name', default='admin'),
161 cfg.StrOpt('certfile'),
162 cfg.StrOpt('keyfile'),
163 cfg.StrOpt('signing_dir'),
164 cfg.ListOpt('memcache_servers'),
165 cfg.IntOpt('token_cache_time', default=300),
166]
167CONF.register_opts(opts, group='keystone_authtoken')
168
169
170def will_expire_soon(expiry):
171 """ Determines if expiration is about to occur.
172
173 :param expiry: a datetime of the expected expiration
174 :returns: boolean : true if expiration is within 30 seconds
175 """
176 soon = (timeutils.utcnow() + datetime.timedelta(seconds=30))
177 return expiry < soon
178
179
180class InvalidUserToken(Exception):
181 pass
182
183
184class ServiceError(Exception):
185 pass
186
187
188class ConfigurationError(Exception):
189 pass
190
191
192class AuthProtocol(object):
193 """Auth Middleware that handles authenticating client calls."""
194
195 def __init__(self, app, conf):
196 LOG.info('Starting keystone auth_token middleware')
197 self.conf = conf
198 self.app = app
199
200 # delay_auth_decision means we still allow unauthenticated requests
201 # through and we let the downstream service make the final decision
202 self.delay_auth_decision = (self._conf_get('delay_auth_decision') in
203 (True, 'true', 't', '1', 'on', 'yes', 'y'))
204
205 # where to find the auth service (we use this to validate tokens)
206 self.auth_host = self._conf_get('auth_host')
207 self.auth_port = int(self._conf_get('auth_port'))
208 self.auth_protocol = self._conf_get('auth_protocol')
209 if self.auth_protocol == 'http':
210 self.http_client_class = httplib.HTTPConnection
211 else:
212 self.http_client_class = httplib.HTTPSConnection
213
214 self.auth_admin_prefix = self._conf_get('auth_admin_prefix')
215 self.auth_uri = self._conf_get('auth_uri')
216 if self.auth_uri is None:
217 self.auth_uri = '%s://%s:%s' % (self.auth_protocol,
218 self.auth_host,
219 self.auth_port)
220
221 # SSL
222 self.cert_file = self._conf_get('certfile')
223 self.key_file = self._conf_get('keyfile')
224
225 #signing
226 self.signing_dirname = self._conf_get('signing_dir')
227 if self.signing_dirname is None:
228 self.signing_dirname = '%s/keystone-signing' % os.environ['HOME']
229 LOG.info('Using %s as cache directory for signing certificate' %
230 self.signing_dirname)
231 if (os.path.exists(self.signing_dirname) and
232 not os.access(self.signing_dirname, os.W_OK)):
233 raise ConfigurationError("unable to access signing dir %s" %
234 self.signing_dirname)
235
236 if not os.path.exists(self.signing_dirname):
237 os.makedirs(self.signing_dirname)
238 #will throw IOError if it cannot change permissions
239 os.chmod(self.signing_dirname, stat.S_IRWXU)
240
241 val = '%s/signing_cert.pem' % self.signing_dirname
242 self.signing_cert_file_name = val
243 val = '%s/cacert.pem' % self.signing_dirname
244 self.ca_file_name = val
245 val = '%s/revoked.pem' % self.signing_dirname
246 self.revoked_file_name = val
247
248 # Credentials used to verify this component with the Auth service since
249 # validating tokens is a privileged call
250 self.admin_token = self._conf_get('admin_token')
251 self.admin_token_expiry = None
252 self.admin_user = self._conf_get('admin_user')
253 self.admin_password = self._conf_get('admin_password')
254 self.admin_tenant_name = self._conf_get('admin_tenant_name')
255
256 # Token caching via memcache
257 self._cache = None
258 self._iso8601 = None
259 memcache_servers = self._conf_get('memcache_servers')
260 # By default the token will be cached for 5 minutes
261 self.token_cache_time = int(self._conf_get('token_cache_time'))
262 self._token_revocation_list = None
263 self._token_revocation_list_fetched_time = None
264 cache_timeout = datetime.timedelta(seconds=0)
265 self.token_revocation_list_cache_timeout = cache_timeout
266 if memcache_servers:
267 try:
268 import memcache
269 import iso8601
270 LOG.info('Using memcache for caching token')
271 self._cache = memcache.Client(memcache_servers.split(','))
272 self._iso8601 = iso8601
273 except ImportError as e:
274 LOG.warn('disabled caching due to missing libraries %s', e)
275
276 def _conf_get(self, name):
277 # try config from paste-deploy first
278 if name in self.conf:
279 return self.conf[name]
280 else:
281 return CONF.keystone_authtoken[name]
282
283 def __call__(self, env, start_response):
284 """Handle incoming request.
285
286 Authenticate send downstream on success. Reject request if
287 we can't authenticate.
288
289 """
290 LOG.debug('Authenticating user token')
291 try:
292 self._remove_auth_headers(env)
293 user_token = self._get_user_token_from_header(env)
294 token_info = self._validate_user_token(user_token)
295 env['keystone.token_info'] = token_info
296 user_headers = self._build_user_headers(token_info)
297 self._add_headers(env, user_headers)
298 return self.app(env, start_response)
299
300 except InvalidUserToken:
301 if self.delay_auth_decision:
302 LOG.info('Invalid user token - deferring reject downstream')
303 self._add_headers(env, {'X-Identity-Status': 'Invalid'})
304 return self.app(env, start_response)
305 else:
306 LOG.info('Invalid user token - rejecting request')
307 return self._reject_request(env, start_response)
308
309 except ServiceError as e:
310 LOG.critical('Unable to obtain admin token: %s' % e)
311 resp = webob.exc.HTTPServiceUnavailable()
312 return resp(env, start_response)
313
314 def _remove_auth_headers(self, env):
315 """Remove headers so a user can't fake authentication.
316
317 :param env: wsgi request environment
318
319 """
320 auth_headers = (
321 'X-Identity-Status',
322 'X-Tenant-Id',
323 'X-Tenant-Name',
324 'X-User-Id',
325 'X-User-Name',
326 'X-Roles',
327 'X-Service-Catalog',
328 # Deprecated
329 'X-User',
330 'X-Tenant',
331 'X-Role',
332 )
333 LOG.debug('Removing headers from request environment: %s' %
334 ','.join(auth_headers))
335 self._remove_headers(env, auth_headers)
336
337 def _get_user_token_from_header(self, env):
338 """Get token id from request.
339
340 :param env: wsgi request environment
341 :return token id
342 :raises InvalidUserToken if no token is provided in request
343
344 """
345 token = self._get_header(env, 'X-Auth-Token',
346 self._get_header(env, 'X-Storage-Token'))
347 if token:
348 return token
349 else:
350 LOG.warn("Unable to find authentication token in headers: %s", env)
351 raise InvalidUserToken('Unable to find token in headers')
352
353 def _reject_request(self, env, start_response):
354 """Redirect client to auth server.
355
356 :param env: wsgi request environment
357 :param start_response: wsgi response callback
358 :returns HTTPUnauthorized http response
359
360 """
361 headers = [('WWW-Authenticate', 'Keystone uri=\'%s\'' % self.auth_uri)]
362 resp = webob.exc.HTTPUnauthorized('Authentication required', headers)
363 return resp(env, start_response)
364
365 def get_admin_token(self):
366 """Return admin token, possibly fetching a new one.
367
368 if self.admin_token_expiry is set from fetching an admin token, check
369 it for expiration, and request a new token is the existing token
370 is about to expire.
371
372 :return admin token id
373 :raise ServiceError when unable to retrieve token from keystone
374
375 """
376 if self.admin_token_expiry:
377 if will_expire_soon(self.admin_token_expiry):
378 self.admin_token = None
379
380 if not self.admin_token:
381 (self.admin_token,
382 self.admin_token_expiry) = self._request_admin_token()
383
384 return self.admin_token
385
386 def _get_http_connection(self):
387 if self.auth_protocol == 'http':
388 return self.http_client_class(self.auth_host, self.auth_port)
389 else:
390 return self.http_client_class(self.auth_host,
391 self.auth_port,
392 self.key_file,
393 self.cert_file)
394
395 def _http_request(self, method, path):
396 """HTTP request helper used to make unspecified content type requests.
397
398 :param method: http method
399 :param path: relative request url
400 :return (http response object)
401 :raise ServerError when unable to communicate with keystone
402
403 """
404 conn = self._get_http_connection()
405
406 try:
407 conn.request(method, path)
408 response = conn.getresponse()
409 body = response.read()
410 except Exception as e:
411 LOG.error('HTTP connection exception: %s' % e)
412 raise ServiceError('Unable to communicate with keystone')
413 finally:
414 conn.close()
415
416 return response, body
417
418 def _json_request(self, method, path, body=None, additional_headers=None):
419 """HTTP request helper used to make json requests.
420
421 :param method: http method
422 :param path: relative request url
423 :param body: dict to encode to json as request body. Optional.
424 :param additional_headers: dict of additional headers to send with
425 http request. Optional.
426 :return (http response object, response body parsed as json)
427 :raise ServerError when unable to communicate with keystone
428
429 """
430 conn = self._get_http_connection()
431
432 kwargs = {
433 'headers': {
434 'Content-type': 'application/json',
435 'Accept': 'application/json',
436 },
437 }
438
439 if additional_headers:
440 kwargs['headers'].update(additional_headers)
441
442 if body:
443 kwargs['body'] = jsonutils.dumps(body)
444
445 full_path = self.auth_admin_prefix + path
446 try:
447 conn.request(method, full_path, **kwargs)
448 response = conn.getresponse()
449 body = response.read()
450 except Exception as e:
451 LOG.error('HTTP connection exception: %s' % e)
452 raise ServiceError('Unable to communicate with keystone')
453 finally:
454 conn.close()
455
456 try:
457 data = jsonutils.loads(body)
458 except ValueError:
459 LOG.debug('Keystone did not return json-encoded body')
460 data = {}
461
462 return response, data
463
464 def _request_admin_token(self):
465 """Retrieve new token as admin user from keystone.
466
467 :return token id upon success
468 :raises ServerError when unable to communicate with keystone
469
470 """
471 params = {
472 'auth': {
473 'passwordCredentials': {
474 'username': self.admin_user,
475 'password': self.admin_password,
476 },
477 'tenantName': self.admin_tenant_name,
478 }
479 }
480
481 response, data = self._json_request('POST',
482 '/v2.0/tokens',
483 body=params)
484
485 try:
486 token = data['access']['token']['id']
487 expiry = data['access']['token']['expires']
488 assert token
489 assert expiry
490 datetime_expiry = timeutils.parse_isotime(expiry)
491 return (token, timeutils.normalize_time(datetime_expiry))
492 except (AssertionError, KeyError):
493 LOG.warn("Unexpected response from keystone service: %s", data)
494 raise ServiceError('invalid json response')
495 except (ValueError):
496 LOG.warn("Unable to parse expiration time from token: %s", data)
497 raise ServiceError('invalid json response')
498
499 def _validate_user_token(self, user_token, retry=True):
500 """Authenticate user using PKI
501
502 :param user_token: user's token id
503 :param retry: Ignored, as it is not longer relevant
504 :return uncrypted body of the token if the token is valid
505 :raise InvalidUserToken if token is rejected
506 :no longer raises ServiceError since it no longer makes RPC
507
508 """
509 try:
510 token_id = cms.cms_hash_token(user_token)
511 cached = self._cache_get(token_id)
512 if cached:
513 return cached
514 if cms.is_ans1_token(user_token):
515 verified = self.verify_signed_token(user_token)
516 data = json.loads(verified)
517 else:
518 data = self.verify_uuid_token(user_token, retry)
519 self._cache_put(token_id, data)
520 return data
521 except Exception as e:
522 LOG.debug('Token validation failure.', exc_info=True)
523 self._cache_store_invalid(user_token)
524 LOG.warn("Authorization failed for token %s", user_token)
525 raise InvalidUserToken('Token authorization failed')
526
527 def _build_user_headers(self, token_info):
528 """Convert token object into headers.
529
530 Build headers that represent authenticated user:
531 * X_IDENTITY_STATUS: Confirmed or Invalid
532 * X_TENANT_ID: id of tenant if tenant is present
533 * X_TENANT_NAME: name of tenant if tenant is present
534 * X_USER_ID: id of user
535 * X_USER_NAME: name of user
536 * X_ROLES: list of roles
537 * X_SERVICE_CATALOG: service catalog
538
539 Additional (deprecated) headers include:
540 * X_USER: name of user
541 * X_TENANT: For legacy compatibility before we had ID and Name
542 * X_ROLE: list of roles
543
544 :param token_info: token object returned by keystone on authentication
545 :raise InvalidUserToken when unable to parse token object
546
547 """
548 user = token_info['access']['user']
549 token = token_info['access']['token']
550 roles = ','.join([role['name'] for role in user.get('roles', [])])
551
552 def get_tenant_info():
553 """Returns a (tenant_id, tenant_name) tuple from context."""
554 def essex():
555 """Essex puts the tenant ID and name on the token."""
556 return (token['tenant']['id'], token['tenant']['name'])
557
558 def pre_diablo():
559 """Pre-diablo, Keystone only provided tenantId."""
560 return (token['tenantId'], token['tenantId'])
561
562 def default_tenant():
563 """Assume the user's default tenant."""
564 return (user['tenantId'], user['tenantName'])
565
566 for method in [essex, pre_diablo, default_tenant]:
567 try:
568 return method()
569 except KeyError:
570 pass
571
572 raise InvalidUserToken('Unable to determine tenancy.')
573
574 tenant_id, tenant_name = get_tenant_info()
575
576 user_id = user['id']
577 user_name = user['name']
578
579 rval = {
580 'X-Identity-Status': 'Confirmed',
581 'X-Tenant-Id': tenant_id,
582 'X-Tenant-Name': tenant_name,
583 'X-User-Id': user_id,
584 'X-User-Name': user_name,
585 'X-Roles': roles,
586 # Deprecated
587 'X-User': user_name,
588 'X-Tenant': tenant_name,
589 'X-Role': roles,
590 }
591
592 try:
593 catalog = token_info['access']['serviceCatalog']
594 rval['X-Service-Catalog'] = jsonutils.dumps(catalog)
595 except KeyError:
596 pass
597
598 return rval
599
600 def _header_to_env_var(self, key):
601 """Convert header to wsgi env variable.
602
603 :param key: http header name (ex. 'X-Auth-Token')
604 :return wsgi env variable name (ex. 'HTTP_X_AUTH_TOKEN')
605
606 """
607 return 'HTTP_%s' % key.replace('-', '_').upper()
608
609 def _add_headers(self, env, headers):
610 """Add http headers to environment."""
611 for (k, v) in headers.iteritems():
612 env_key = self._header_to_env_var(k)
613 env[env_key] = v
614
615 def _remove_headers(self, env, keys):
616 """Remove http headers from environment."""
617 for k in keys:
618 env_key = self._header_to_env_var(k)
619 try:
620 del env[env_key]
621 except KeyError:
622 pass
623
624 def _get_header(self, env, key, default=None):
625 """Get http header from environment."""
626 env_key = self._header_to_env_var(key)
627 return env.get(env_key, default)
628
629 def _cache_get(self, token):
630 """Return token information from cache.
631
632 If token is invalid raise InvalidUserToken
633 return token only if fresh (not expired).
634 """
635 if self._cache and token:
636 key = 'tokens/%s' % token
637 cached = self._cache.get(key)
638 if cached == 'invalid':
639 LOG.debug('Cached Token %s is marked unauthorized', token)
640 raise InvalidUserToken('Token authorization failed')
641 if cached:
642 data, expires = cached
643 if time.time() < float(expires):
644 LOG.debug('Returning cached token %s', token)
645 return data
646 else:
647 LOG.debug('Cached Token %s seems expired', token)
648
649 def _cache_put(self, token, data):
650 """Put token data into the cache.
651
652 Stores the parsed expire date in cache allowing
653 quick check of token freshness on retrieval.
654 """
655 if self._cache and data:
656 key = 'tokens/%s' % token
657 if 'token' in data.get('access', {}):
658 timestamp = data['access']['token']['expires']
659 expires = self._iso8601.parse_date(timestamp).strftime('%s')
660 else:
661 LOG.error('invalid token format')
662 return
663 LOG.debug('Storing %s token in memcache', token)
664 self._cache.set(key,
665 (data, expires),
666 time=self.token_cache_time)
667
668 def _cache_store_invalid(self, token):
669 """Store invalid token in cache."""
670 if self._cache:
671 key = 'tokens/%s' % token
672 LOG.debug('Marking token %s as unauthorized in memcache', token)
673 self._cache.set(key,
674 'invalid',
675 time=self.token_cache_time)
676
677 def cert_file_missing(self, called_proc_err, file_name):
678 return (called_proc_err.output.find(file_name)
679 and not os.path.exists(file_name))
680
681 def verify_uuid_token(self, user_token, retry=True):
682 """Authenticate user token with keystone.
683
684 :param user_token: user's token id
685 :param retry: flag that forces the middleware to retry
686 user authentication when an indeterminate
687 response is received. Optional.
688 :return token object received from keystone on success
689 :raise InvalidUserToken if token is rejected
690 :raise ServiceError if unable to authenticate token
691
692 """
693
694 headers = {'X-Auth-Token': self.get_admin_token()}
695 response, data = self._json_request('GET',
696 '/v2.0/tokens/%s' % user_token,
697 additional_headers=headers)
698
699 if response.status == 200:
700 self._cache_put(user_token, data)
701 return data
702 if response.status == 404:
703 # FIXME(ja): I'm assuming the 404 status means that user_token is
704 # invalid - not that the admin_token is invalid
705 self._cache_store_invalid(user_token)
706 LOG.warn("Authorization failed for token %s", user_token)
707 raise InvalidUserToken('Token authorization failed')
708 if response.status == 401:
709 LOG.info('Keystone rejected admin token %s, resetting', headers)
710 self.admin_token = None
711 else:
712 LOG.error('Bad response code while validating token: %s' %
713 response.status)
714 if retry:
715 LOG.info('Retrying validation')
716 return self._validate_user_token(user_token, False)
717 else:
718 LOG.warn("Invalid user token: %s. Keystone response: %s.",
719 user_token, data)
720
721 raise InvalidUserToken()
722
723 def is_signed_token_revoked(self, signed_text):
724 """Indicate whether the token appears in the revocation list."""
725 revocation_list = self.token_revocation_list
726 revoked_tokens = revocation_list.get('revoked', [])
727 if not revoked_tokens:
728 return
729 revoked_ids = (x['id'] for x in revoked_tokens)
730 token_id = utils.hash_signed_token(signed_text)
731 for revoked_id in revoked_ids:
732 if token_id == revoked_id:
733 LOG.debug('Token %s is marked as having been revoked',
734 token_id)
735 return True
736 return False
737
738 def cms_verify(self, data):
739 """Verifies the signature of the provided data's IAW CMS syntax.
740
741 If either of the certificate files are missing, fetch them and
742 retry.
743 """
744 while True:
745 try:
746 output = cms.cms_verify(data, self.signing_cert_file_name,
747 self.ca_file_name)
748 except cms.subprocess.CalledProcessError as err:
749 if self.cert_file_missing(err, self.signing_cert_file_name):
750 self.fetch_signing_cert()
751 continue
752 if self.cert_file_missing(err, self.ca_file_name):
753 self.fetch_ca_cert()
754 continue
755 raise err
756 return output
757
758 def verify_signed_token(self, signed_text):
759 """Check that the token is unrevoked and has a valid signature."""
760 if self.is_signed_token_revoked(signed_text):
761 raise InvalidUserToken('Token has been revoked')
762
763 formatted = cms.token_to_cms(signed_text)
764 return self.cms_verify(formatted)
765
766 @property
767 def token_revocation_list_fetched_time(self):
768 if not self._token_revocation_list_fetched_time:
769 # If the fetched list has been written to disk, use its
770 # modification time.
771 if os.path.exists(self.revoked_file_name):
772 mtime = os.path.getmtime(self.revoked_file_name)
773 fetched_time = datetime.datetime.fromtimestamp(mtime)
774 # Otherwise the list will need to be fetched.
775 else:
776 fetched_time = datetime.datetime.min
777 self._token_revocation_list_fetched_time = fetched_time
778 return self._token_revocation_list_fetched_time
779
780 @token_revocation_list_fetched_time.setter
781 def token_revocation_list_fetched_time(self, value):
782 self._token_revocation_list_fetched_time = value
783
784 @property
785 def token_revocation_list(self):
786 timeout = (self.token_revocation_list_fetched_time +
787 self.token_revocation_list_cache_timeout)
788 list_is_current = timeutils.utcnow() < timeout
789 if list_is_current:
790 # Load the list from disk if required
791 if not self._token_revocation_list:
792 with open(self.revoked_file_name, 'r') as f:
793 self._token_revocation_list = jsonutils.loads(f.read())
794 else:
795 self.token_revocation_list = self.fetch_revocation_list()
796 return self._token_revocation_list
797
798 @token_revocation_list.setter
799 def token_revocation_list(self, value):
800 """Save a revocation list to memory and to disk.
801
802 :param value: A json-encoded revocation list
803
804 """
805 self._token_revocation_list = jsonutils.loads(value)
806 self.token_revocation_list_fetched_time = timeutils.utcnow()
807 with open(self.revoked_file_name, 'w') as f:
808 f.write(value)
809
810 def fetch_revocation_list(self, retry=True):
811 headers = {'X-Auth-Token': self.get_admin_token()}
812 response, data = self._json_request('GET', '/v2.0/tokens/revoked',
813 additional_headers=headers)
814 if response.status == 401:
815 if retry:
816 LOG.info('Keystone rejected admin token %s, resetting admin '
817 'token', headers)
818 self.admin_token = None
819 return self.fetch_revocation_list(retry=False)
820 if response.status != 200:
821 raise ServiceError('Unable to fetch token revocation list.')
822 if (not 'signed' in data):
823 raise ServiceError('Revocation list inmproperly formatted.')
824 return self.cms_verify(data['signed'])
825
826 def fetch_signing_cert(self):
827 response, data = self._http_request('GET',
828 '/v2.0/certificates/signing')
829 try:
830 #todo check response
831 certfile = open(self.signing_cert_file_name, 'w')
832 certfile.write(data)
833 certfile.close()
834 except (AssertionError, KeyError):
835 LOG.warn("Unexpected response from keystone service: %s", data)
836 raise ServiceError('invalid json response')
837
838 def fetch_ca_cert(self):
839 response, data = self._http_request('GET',
840 '/v2.0/certificates/ca')
841 try:
842 #todo check response
843 certfile = open(self.ca_file_name, 'w')
844 certfile.write(data)
845 certfile.close()
846 except (AssertionError, KeyError):
847 LOG.warn("Unexpected response from keystone service: %s", data)
848 raise ServiceError('invalid json response')
849
850
851def filter_factory(global_conf, **local_conf):
852 """Returns a WSGI filter app for use with paste.deploy."""
853 conf = global_conf.copy()
854 conf.update(local_conf)
855
856 def auth_filter(app):
857 return AuthProtocol(app, conf)
858 return auth_filter
859
860
861def app_factory(global_conf, **local_conf):
862 conf = global_conf.copy()
863 conf.update(local_conf)
864 return AuthProtocol(None, conf)
0865
=== added file 'keystoneclient/middleware/test.py'
--- keystoneclient/middleware/test.py 1970-01-01 00:00:00 +0000
+++ keystoneclient/middleware/test.py 2012-11-30 14:11:19 +0000
@@ -0,0 +1,67 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 OpenStack LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17#
18# Test support for middleware authentication
19#
20
21import os
22import sys
23
24
25ROOTDIR = os.path.dirname(os.path.abspath(os.curdir))
26
27
28def rootdir(*p):
29 return os.path.join(ROOTDIR, *p)
30
31
32class NoModule(object):
33 """A mixin class to provide support for unloading/disabling modules."""
34
35 def __init__(self, *args, **kw):
36 super(NoModule, self).__init__(*args, **kw)
37 self._finders = []
38 self._cleared_modules = {}
39
40 def tearDown(self):
41 super(NoModule, self).tearDown()
42 for finder in self._finders:
43 sys.meta_path.remove(finder)
44 sys.modules.update(self._cleared_modules)
45
46 def clear_module(self, module):
47 cleared_modules = {}
48 for fullname in sys.modules.keys():
49 if fullname == module or fullname.startswith(module + '.'):
50 cleared_modules[fullname] = sys.modules.pop(fullname)
51 return cleared_modules
52
53 def disable_module(self, module):
54 """Ensure ImportError for the specified module."""
55
56 # Clear 'module' references in sys.modules
57 self._cleared_modules.update(self.clear_module(module))
58
59 # Disallow further imports of 'module'
60 class NoModule(object):
61 def find_module(self, fullname, path):
62 if fullname == module or fullname.startswith(module + '.'):
63 raise ImportError
64
65 finder = NoModule()
66 self._finders.append(finder)
67 sys.meta_path.insert(0, finder)
068
=== added file 'keystoneclient/openstack/common/cfg.py'
--- keystoneclient/openstack/common/cfg.py 1970-01-01 00:00:00 +0000
+++ keystoneclient/openstack/common/cfg.py 2012-11-30 14:11:19 +0000
@@ -0,0 +1,1653 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2012 Red Hat, Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
17r"""
18Configuration options which may be set on the command line or in config files.
19
20The schema for each option is defined using the Opt sub-classes, e.g.:
21
22::
23
24 common_opts = [
25 cfg.StrOpt('bind_host',
26 default='0.0.0.0',
27 help='IP address to listen on'),
28 cfg.IntOpt('bind_port',
29 default=9292,
30 help='Port number to listen on')
31 ]
32
33Options can be strings, integers, floats, booleans, lists or 'multi strings'::
34
35 enabled_apis_opt = cfg.ListOpt('enabled_apis',
36 default=['ec2', 'osapi_compute'],
37 help='List of APIs to enable by default')
38
39 DEFAULT_EXTENSIONS = [
40 'nova.api.openstack.compute.contrib.standard_extensions'
41 ]
42 osapi_compute_extension_opt = cfg.MultiStrOpt('osapi_compute_extension',
43 default=DEFAULT_EXTENSIONS)
44
45Option schemas are registered with the config manager at runtime, but before
46the option is referenced::
47
48 class ExtensionManager(object):
49
50 enabled_apis_opt = cfg.ListOpt(...)
51
52 def __init__(self, conf):
53 self.conf = conf
54 self.conf.register_opt(enabled_apis_opt)
55 ...
56
57 def _load_extensions(self):
58 for ext_factory in self.conf.osapi_compute_extension:
59 ....
60
61A common usage pattern is for each option schema to be defined in the module or
62class which uses the option::
63
64 opts = ...
65
66 def add_common_opts(conf):
67 conf.register_opts(opts)
68
69 def get_bind_host(conf):
70 return conf.bind_host
71
72 def get_bind_port(conf):
73 return conf.bind_port
74
75An option may optionally be made available via the command line. Such options
76must registered with the config manager before the command line is parsed (for
77the purposes of --help and CLI arg validation)::
78
79 cli_opts = [
80 cfg.BoolOpt('verbose',
81 short='v',
82 default=False,
83 help='Print more verbose output'),
84 cfg.BoolOpt('debug',
85 short='d',
86 default=False,
87 help='Print debugging output'),
88 ]
89
90 def add_common_opts(conf):
91 conf.register_cli_opts(cli_opts)
92
93The config manager has two CLI options defined by default, --config-file
94and --config-dir::
95
96 class ConfigOpts(object):
97
98 def __call__(self, ...):
99
100 opts = [
101 MultiStrOpt('config-file',
102 ...),
103 StrOpt('config-dir',
104 ...),
105 ]
106
107 self.register_cli_opts(opts)
108
109Option values are parsed from any supplied config files using
110openstack.common.iniparser. If none are specified, a default set is used
111e.g. glance-api.conf and glance-common.conf::
112
113 glance-api.conf:
114 [DEFAULT]
115 bind_port = 9292
116
117 glance-common.conf:
118 [DEFAULT]
119 bind_host = 0.0.0.0
120
121Option values in config files override those on the command line. Config files
122are parsed in order, with values in later files overriding those in earlier
123files.
124
125The parsing of CLI args and config files is initiated by invoking the config
126manager e.g.::
127
128 conf = ConfigOpts()
129 conf.register_opt(BoolOpt('verbose', ...))
130 conf(sys.argv[1:])
131 if conf.verbose:
132 ...
133
134Options can be registered as belonging to a group::
135
136 rabbit_group = cfg.OptGroup(name='rabbit',
137 title='RabbitMQ options')
138
139 rabbit_host_opt = cfg.StrOpt('host',
140 default='localhost',
141 help='IP/hostname to listen on'),
142 rabbit_port_opt = cfg.IntOpt('port',
143 default=5672,
144 help='Port number to listen on')
145
146 def register_rabbit_opts(conf):
147 conf.register_group(rabbit_group)
148 # options can be registered under a group in either of these ways:
149 conf.register_opt(rabbit_host_opt, group=rabbit_group)
150 conf.register_opt(rabbit_port_opt, group='rabbit')
151
152If it no group attributes are required other than the group name, the group
153need not be explicitly registered e.g.
154
155 def register_rabbit_opts(conf):
156 # The group will automatically be created, equivalent calling::
157 # conf.register_group(OptGroup(name='rabbit'))
158 conf.register_opt(rabbit_port_opt, group='rabbit')
159
160If no group is specified, options belong to the 'DEFAULT' section of config
161files::
162
163 glance-api.conf:
164 [DEFAULT]
165 bind_port = 9292
166 ...
167
168 [rabbit]
169 host = localhost
170 port = 5672
171 use_ssl = False
172 userid = guest
173 password = guest
174 virtual_host = /
175
176Command-line options in a group are automatically prefixed with the
177group name::
178
179 --rabbit-host localhost --rabbit-port 9999
180
181Option values in the default group are referenced as attributes/properties on
182the config manager; groups are also attributes on the config manager, with
183attributes for each of the options associated with the group::
184
185 server.start(app, conf.bind_port, conf.bind_host, conf)
186
187 self.connection = kombu.connection.BrokerConnection(
188 hostname=conf.rabbit.host,
189 port=conf.rabbit.port,
190 ...)
191
192Option values may reference other values using PEP 292 string substitution::
193
194 opts = [
195 cfg.StrOpt('state_path',
196 default=os.path.join(os.path.dirname(__file__), '../'),
197 help='Top-level directory for maintaining nova state'),
198 cfg.StrOpt('sqlite_db',
199 default='nova.sqlite',
200 help='file name for sqlite'),
201 cfg.StrOpt('sql_connection',
202 default='sqlite:///$state_path/$sqlite_db',
203 help='connection string for sql database'),
204 ]
205
206Note that interpolation can be avoided by using '$$'.
207
208For command line utilities that dispatch to other command line utilities, the
209disable_interspersed_args() method is available. If this this method is called,
210then parsing e.g.::
211
212 script --verbose cmd --debug /tmp/mything
213
214will no longer return::
215
216 ['cmd', '/tmp/mything']
217
218as the leftover arguments, but will instead return::
219
220 ['cmd', '--debug', '/tmp/mything']
221
222i.e. argument parsing is stopped at the first non-option argument.
223
224Options may be declared as required so that an error is raised if the user
225does not supply a value for the option.
226
227Options may be declared as secret so that their values are not leaked into
228log files:
229
230 opts = [
231 cfg.StrOpt('s3_store_access_key', secret=True),
232 cfg.StrOpt('s3_store_secret_key', secret=True),
233 ...
234 ]
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches