summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGordon Chung <chungg@ca.ibm.com>2013-02-21 15:52:12 -0500
committerGordon Chung <chungg@ca.ibm.com>2013-03-07 17:06:38 -0500
commitdd7d4fd551f727873462d3ef2ece863ab6400995 (patch)
tree67032fdfcd41e89ef63b5541c116f22055ab5990
parent2b49a0ad13a4aca086474f101b104ac562e1f2f0 (diff)
return 201 Created on POST request (bug1131119)
correct status code from 200 Ok to 201 Created for v3 POST requests. Fixes: bug #1131119 Change-Id: Iabeb6daf677e0f34defdef5e58d87229fc90346f
-rw-r--r--keystone/auth/controllers.py4
-rw-r--r--keystone/auth/token_factory.py9
-rw-r--r--keystone/common/wsgi.py13
-rw-r--r--tests/test_content_types.py2
-rw-r--r--tests/test_v3.py30
5 files changed, 45 insertions, 13 deletions
diff --git a/keystone/auth/controllers.py b/keystone/auth/controllers.py
index 96f3dc0c..ec532b1b 100644
--- a/keystone/auth/controllers.py
+++ b/keystone/auth/controllers.py
@@ -294,8 +294,8 @@ class Auth(controller.V3Controller):
auth_context)
(token_id, token_data) = token_factory.create_token(
context, auth_context, auth_info)
- return token_factory.render_token_data_response(token_id,
- token_data)
+ return token_factory.render_token_data_response(
+ token_id, token_data, created=True)
except (exception.Unauthorized,
exception.AuthMethodNotSupported,
exception.AdditionalAuthRequired) as e:
diff --git a/keystone/auth/token_factory.py b/keystone/auth/token_factory.py
index 8460aec6..4d5c0b87 100644
--- a/keystone/auth/token_factory.py
+++ b/keystone/auth/token_factory.py
@@ -294,7 +294,7 @@ def create_token(context, auth_context, auth_info):
return (token_id, token_data)
-def render_token_data_response(token_id, token_data):
+def render_token_data_response(token_id, token_data, created=False):
""" Render token data HTTP response.
Stash token ID into the X-Auth-Token header.
@@ -303,7 +303,12 @@ def render_token_data_response(token_id, token_data):
headers = [('X-Subject-Token', token_id)]
headers.append(('Vary', 'X-Auth-Token'))
headers.append(('Content-Type', 'application/json'))
- status = (200, 'OK')
+
+ if created:
+ status = (201, 'Created')
+ else:
+ status = (200, 'OK')
+
body = jsonutils.dumps(token_data, cls=utils.SmarterEncoder)
return webob.Response(body=body,
status='%s %s' % status,
diff --git a/keystone/common/wsgi.py b/keystone/common/wsgi.py
index 108cc0ca..672a82f3 100644
--- a/keystone/common/wsgi.py
+++ b/keystone/common/wsgi.py
@@ -33,6 +33,7 @@ from keystone.common import logging
from keystone.common import utils
from keystone import config
from keystone import exception
+from keystone.openstack.common import importutils
from keystone.openstack.common import jsonutils
@@ -251,7 +252,17 @@ class Application(BaseApplication):
return result
elif isinstance(result, webob.exc.WSGIHTTPException):
return result
- return render_response(body=result)
+
+ response_code = self._get_response_code(req)
+ return render_response(body=result, status=response_code)
+
+ def _get_response_code(self, req):
+ req_method = req.environ['REQUEST_METHOD']
+ controller = importutils.import_class('keystone.common.controller')
+ code = None
+ if isinstance(self, controller.V3Controller) and req_method == 'POST':
+ code = (201, 'Created')
+ return code
def _normalize_arg(self, arg):
return str(arg).replace(':', '_').replace('-', '_')
diff --git a/tests/test_content_types.py b/tests/test_content_types.py
index e0b42db9..a5457ccb 100644
--- a/tests/test_content_types.py
+++ b/tests/test_content_types.py
@@ -373,7 +373,6 @@ class CoreApiTests(object):
'tenantId': self.tenant_bar['id'],
},
},
- # TODO(dolph): creating a token should result in a 201 Created
expected_status=200)
self.assertValidAuthenticationResponse(r)
@@ -389,7 +388,6 @@ class CoreApiTests(object):
},
},
},
- # TODO(dolph): creating a token should result in a 201 Created
expected_status=200)
self.assertValidAuthenticationResponse(r)
diff --git a/tests/test_v3.py b/tests/test_v3.py
index 39807cec..9b4f7d34 100644
--- a/tests/test_v3.py
+++ b/tests/test_v3.py
@@ -221,22 +221,40 @@ class RestfulTestCase(test_content_types.RestfulTestCase):
**kwargs)
def get(self, path, **kwargs):
- return self.v3_request(method='GET', path=path, **kwargs)
+ r = self.v3_request(method='GET', path=path, **kwargs)
+ if 'expected_status' not in kwargs:
+ self.assertResponseStatus(r, 200)
+ return r
def head(self, path, **kwargs):
- return self.v3_request(method='HEAD', path=path, **kwargs)
+ r = self.v3_request(method='HEAD', path=path, **kwargs)
+ if 'expected_status' not in kwargs:
+ self.assertResponseStatus(r, 204)
+ return r
def post(self, path, **kwargs):
- return self.v3_request(method='POST', path=path, **kwargs)
+ r = self.v3_request(method='POST', path=path, **kwargs)
+ if 'expected_status' not in kwargs:
+ self.assertResponseStatus(r, 201)
+ return r
def put(self, path, **kwargs):
- return self.v3_request(method='PUT', path=path, **kwargs)
+ r = self.v3_request(method='PUT', path=path, **kwargs)
+ if 'expected_status' not in kwargs:
+ self.assertResponseStatus(r, 204)
+ return r
def patch(self, path, **kwargs):
- return self.v3_request(method='PATCH', path=path, **kwargs)
+ r = self.v3_request(method='PATCH', path=path, **kwargs)
+ if 'expected_status' not in kwargs:
+ self.assertResponseStatus(r, 200)
+ return r
def delete(self, path, **kwargs):
- return self.v3_request(method='DELETE', path=path, **kwargs)
+ r = self.v3_request(method='DELETE', path=path, **kwargs)
+ if 'expected_status' not in kwargs:
+ self.assertResponseStatus(r, 204)
+ return r
def assertValidErrorResponse(self, r):
if r.getheader('Content-Type') == 'application/xml':