Changing authenticate request content xml as well as json.
Change-Id: I26e67facf6cf535f851164c41c8c5efcac85fa50
This commit is contained in:
parent
6a9361062c
commit
012b2125fb
1
AUTHORS
1
AUTHORS
@ -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>
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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__':
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user