Changing authenticate request content xml as well as json.

Change-Id: I26e67facf6cf535f851164c41c8c5efcac85fa50
This commit is contained in:
Yogeshwar Srikrishnan 2011-09-20 14:54:53 -05:00 committed by Dolph Mathews
parent 6a9361062c
commit 012b2125fb
10 changed files with 79 additions and 58 deletions

View File

@ -32,4 +32,3 @@ Vishvananda Ishaya <vishvananda@gmail.com>
Yogeshwar Srikrishnan <yoga80@yahoo.com>
Yuriy Taraday <yorik.sar@gmail.com>
Ziad Sawalha <github@highbridgellc.com>

View File

@ -12,10 +12,11 @@ class AuthController(wsgi.Controller):
@utils.wrap_error
def authenticate(self, req):
creds = utils.get_normalized_request_content(
auth.PasswordCredentials, req)
auth_with_credentials = utils.get_normalized_request_content(
auth.AuthWithPasswordCredentials, req)
return utils.send_result(200, req, config.SERVICE.authenticate(creds))
return utils.send_result(200, req,
config.SERVICE.authenticate(auth_with_credentials))
@utils.wrap_error
def authenticate_ec2(self, req):

View File

@ -61,9 +61,9 @@ class AuthProtocol(object):
""" Handle incoming request. Transform. And send downstream. """
request = Request(env)
if env['KEYSTONE_API_VERSION'] in ['1.0', '1.1']:
params = {"passwordCredentials":
params = {"auth": {"passwordCredentials":
{"username": utils.get_auth_user(request),
"password": utils.get_auth_key(request)}}
"password": utils.get_auth_key(request)}}}
#Make request to keystone
new_request = Request.blank('/tokens')
new_request.method = 'POST'

View File

@ -41,19 +41,23 @@ class IdentityService(object):
#
# Token Operations
#
def authenticate(self, credentials):
# Check credentials
if not isinstance(credentials, auth.PasswordCredentials):
raise fault.BadRequestFault("Expecting Password Credentials!")
def authenticate(self, auth_with_password_credentials):
# Check auth_with_password_credentials
if not isinstance(auth_with_password_credentials,
auth.AuthWithPasswordCredentials):
raise fault.BadRequestFault(
"Expecting auth_with_password_credentials!")
def validate(duser):
return api.USER.check_password(duser, credentials.password)
return api.USER.check_password(
duser, auth_with_password_credentials.password)
user = api.USER.get_by_name(credentials.username)
user = api.USER.get_by_name(auth_with_password_credentials.username)
if not user:
raise fault.UnauthorizedFault("Unauthorized")
return self._authenticate(validate, user.id, credentials.tenant_id)
return self._authenticate(
validate, user.id, auth_with_password_credentials.tenant_id)
def authenticate_ec2(self, credentials):
# Check credentials

View File

@ -19,11 +19,7 @@ from lxml import etree
from keystone.logic.types import fault
class PasswordCredentials(object):
"""Credentials based on username, password, and (optional) tenant_id.
To handle multiple token for a user depending on tenants.
"""
class AuthWithPasswordCredentials(object):
def __init__(self, username, password, tenant_id):
self.username = username
self.password = password
@ -35,31 +31,48 @@ class PasswordCredentials(object):
dom = etree.Element("root")
dom.append(etree.fromstring(xml_str))
root = dom.find("{http://docs.openstack.org/identity/api/v2.0}"
"passwordCredentials")
"auth")
if root == None:
raise fault.BadRequestFault("Expecting auth")
tenant_id = root.get("tenantId")
password_credentials = \
root.find("{http://docs.openstack.org/identity/api/v2.0}"
"passwordCredentials")
if password_credentials == None:
raise fault.BadRequestFault("Expecting passwordCredentials")
username = root.get("username")
username = password_credentials.get("username")
if username == None:
raise fault.BadRequestFault("Expecting a username")
password = root.get("password")
password = password_credentials.get("password")
if password == None:
raise fault.BadRequestFault("Expecting a password")
tenant_id = root.get("tenantId")
return PasswordCredentials(username, password, tenant_id)
return AuthWithPasswordCredentials(username, password, tenant_id)
except etree.LxmlError as e:
raise fault.BadRequestFault("Cannot parse password credentials",
raise fault.BadRequestFault("Cannot parse password access",
str(e))
@staticmethod
def from_json(json_str):
try:
obj = json.loads(json_str)
if not "passwordCredentials" in obj:
if not "auth" in obj:
raise fault.BadRequestFault("Expecting auth")
auth = obj["auth"]
invalid = [key for key in auth if key not in\
['tenantId', 'passwordCredentials']]
if invalid != []:
raise fault.BadRequestFault("Invalid attribute(s): %s"
% invalid)
if "tenantId" in auth:
tenant_id = auth["tenantId"]
else:
tenant_id = None
if not "passwordCredentials" in auth:
raise fault.BadRequestFault("Expecting passwordCredentials")
cred = obj["passwordCredentials"]
cred = auth["passwordCredentials"]
# Check that fields are valid
invalid = [key for key in cred if key not in\
['username', 'tenantId', 'password']]
['username', 'password']]
if invalid != []:
raise fault.BadRequestFault("Invalid attribute(s): %s"
% invalid)
@ -69,13 +82,9 @@ class PasswordCredentials(object):
if not "password" in cred:
raise fault.BadRequestFault("Expecting a password")
password = cred["password"]
if "tenantId" in cred:
tenant_id = cred["tenantId"]
else:
tenant_id = None
return PasswordCredentials(username, password, tenant_id)
return AuthWithPasswordCredentials(username, password, tenant_id)
except (ValueError, TypeError) as e:
raise fault.BadRequestFault("Cannot parse password credentials",
raise fault.BadRequestFault("Cannot parse auth",
str(e))

View File

@ -463,12 +463,13 @@ class FunctionalTestCase(ApiTestCase):
user_password = optional_str(user_password)
data = {
"passwordCredentials": {
"auth": {
"passwordCredentials": {
"username": user_name,
"password": user_password}}
"password": user_password}}}
if tenant_id:
data["passwordCredentials"]["tenantId"] = tenant_id
data["auth"]["tenantId"] = tenant_id
return self.post_token(as_json=data, **kwargs)

View File

@ -53,9 +53,10 @@ class TestServiceAuthentication(common.FunctionalTestCase):
"""Admin should be able to validate a user's token"""
# Authenticate as user to get a token
self.service_token = self.post_token(as_json={
'auth': {
'passwordCredentials': {
'username': self.user['name'],
'password': self.user['password']}}).\
'password': self.user['password']}}}).\
json['auth']['token']['id']
# In the real world, the service user would then pass his/her token
@ -87,42 +88,44 @@ class TestServiceAuthentication(common.FunctionalTestCase):
"""Authenticating with an unknown username returns a 401"""
# Authenticate as user to get a token
self.post_token(assert_status=401, as_json={
'passwordCredentials': {
'auth': {'passwordCredentials': {
'username': 'this-is-completely-wrong',
'password': self.user['password']}})
'password': self.user['password']}}})
def test_user_auth_with_no_name(self):
"""Authenticating without a username returns a 401"""
# Authenticate as user to get a token
self.post_token(assert_status=401, as_json={
'passwordCredentials': {
'auth': {'passwordCredentials': {
'username': None,
'password': self.user['password']}})
'password': self.user['password']}}})
def test_user_auth_with_wrong_password(self):
"""Authenticating with an invalid password returns a 401"""
# Authenticate as user to get a token
self.post_token(assert_status=401, as_json={
'passwordCredentials': {
'auth': {'passwordCredentials': {
'username': self.user['name'],
'password': 'this-is-completely-wrong'}})
'password': 'this-is-completely-wrong'}}})
def test_user_auth_with_no_password(self):
"""Authenticating with an invalid password returns a 401"""
# Authenticate as user to get a token
self.post_token(assert_status=401, as_json={
'passwordCredentials': {
'auth': {'passwordCredentials': {
'username': self.user['name'],
'password': None}})
'password': None}}})
def test_user_auth_with_invalid_tenant(self):
"""Authenticating with an invalid password returns a 401"""
# Authenticate as user to get a token
self.post_token(assert_status=401, as_json={
'auth': {
'passwordCredentials': {
'username': self.user['name'],
'password': self.user['password'],
'tenantId': 'this-is-completely-wrong'}})
},
'tenantId': 'this-is-completely-wrong'}})
if __name__ == '__main__':

View File

@ -48,10 +48,11 @@ class AuthenticationTest(common.FunctionalTestCase):
def test_authorize_xml(self):
data = ('<?xml version="1.0" encoding="UTF-8"?> '
'<passwordCredentials xmlns="%s" username="%s" password="%s" '
'tenantId="%s"/> ') % (
self.xmlns, self.user['name'], self.user['password'],
self.tenant['id'])
'<auth xmlns="%s" tenantId="%s">'
'<passwordCredentials username="%s" password="%s" '
'/> </auth>') % (
self.xmlns, self.tenant['id'],
self.user['name'], self.user['password'])
r = self.post_token(as_xml=data, assert_status=200)
self.assertEquals(r.xml.tag, '{%s}auth' % self.xmlns)
@ -74,9 +75,10 @@ class AuthenticationTest(common.FunctionalTestCase):
def test_authorize_user_wrong(self):
data = {
"passwordCredentials": {
"username-field-completely-wrong": self.user['name'],
"password": self.user['password'],
"auth": {
"passwordCredentials": {
"username-field-completely-wrong": self.user['name'],
"password": self.user['password']},
"tenantId": self.tenant['id']}}
self.post_token(as_json=data, assert_status=400)

View File

@ -5,14 +5,15 @@ import keystone.logic.types.auth as auth
class TestAuth(unittest.TestCase):
'''Unit tests for auth.py.'''
pwd_xml = '<?xml version="1.0" encoding="UTF-8"?> \
pwd_xml = '<?xml version="1.0" encoding="UTF-8"?>\
<auth xmlns="http://docs.openstack.org/identity/api/v2.0">\
<passwordCredentials \
xmlns="http://docs.openstack.org/identity/api/v2.0" \
password="secret" username="disabled" \
/>'
/></auth>'
def test_pwd_cred_marshall(self):
creds = auth.PasswordCredentials.from_xml(self.pwd_xml)
creds = auth.AuthWithPasswordCredentials.from_xml(self.pwd_xml)
self.assertTrue(creds.password, "secret")
self.assertTrue(creds.username, "username")

View File

@ -70,12 +70,13 @@ class TestServer(unittest.TestCase):
def test_get_normalized_request_content_xml(self):
self.request.environ["CONTENT_TYPE"] = "application/xml"
auth.PasswordCredentials("username", "password", "1")
auth.AuthWithPasswordCredentials("username", "password", "1")
body = '<?xml version="1.0" encoding="UTF-8"?> \
<auth xmlns="http://docs.openstack.org/identity/api/v2.0">\
<passwordCredentials \
xmlns="http://docs.openstack.org/identity/api/v2.0" \
password="secret" username="disabled" \
/>'
/></auth>'
str = StringIO()
str.write(body)
self.request.environ["wsgi.input"] = str