Second create-tenant request fails with 401 Forbidden
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
OpenStack Identity (keystone) |
Fix Released
|
Medium
|
Dolph Mathews |
Bug Description
I am using the SQLalchemy backend, MySQL 5.0.77, SQLAlchemy 0.6.5, Keystone latest. Note that MySQL and SQLAlchemy may be a bit old (I am using CentOS 5.5 as the base platform, with some backports) so if this turns out not to be a problem on a more modern platform then we may want to just ignore this bug.
I am making create-tenant requests (POST to /v2.0/tenants) as a global admin (i.e. no tenant, admin rights). The first one succeeds as expected. The second one fails with 401 Forbidden and the log message 'User <UUID> failed check - did not have role 1'.
What's happening is this:
1. the first create-tenant request is causing a new tenants row to be created in the database, with an autoincrementing integer in the tenants.id column.
2. When the second request comes in, the access check is calling keystone.
3. TENANT.id_to_uid has no shortcut for id=None. This leads to it making a database query equivalent to "SELECT uid FROM tenant WHERE id IS NULL". This is where things go wrong. This query _should_ return zero rows, because id IS NULL should always be false on an autoincremented integer. However, the query response includes the new tenants row created in step 1. In the database, id has been populated correctly, and is not NULL. SQLalchemy doesn't see that though. The session is clearly caching a row which has the new data submitted to the database, but _not_ the value in the auto-populated id column.
4. This results in TENANT.
5. This state disappears immediately it seems -- subsequent calls to id_to_uuid(None) return None as expected.
I can see a couple of fixes for this:
1. Make id_to_uid(None) shortcut to return None, and therefore never hit the database in that case. This is a good idea for performance reasons anyway (queries of the form 'id IS NULL' should always return zero rows anyway). The reason I'm not proposing that straight away is that it feels like papering over a dangerous crack. There may be other situations that I haven't found yet where the database layer returns the wrong thing.
2. Change sqlalchemy.
description: | updated |
description: | updated |
Changed in keystone: | |
importance: | Undecided → Medium |
Changed in keystone: | |
status: | Fix Committed → Fix Released |
Changed in keystone: | |
milestone: | essex-4 → 2012.1 |
First of all, I agree that a shortcut for None would be an improvement, but I'd still like to reproduce this issue if possible.
I'm in the process of setting up an environment similar to yours, but in the mean time, should a client-side test that amounts to the following be sufficient reproduce?
self. create_ tenant( assert_ status= 201) create_ tenant( assert_ status= 201)
self.