Correctly handle auth_url/token authentication
Previously the client assumed that if a user passed a token then this token should be used for everything. This assumption is correct for the endpoint/token case but not in the auth_url/token case where you will want to fetch a new token. This is needed in the case where you want to use an existing token to fetch a token that is re-scoped or activate a trust. There are still problems such as if you use auth_url/token authentication then when the token expires it will try to refresh it, but authenticating with a token will not extend the token expiry. Closes-Bug: #1257541 Change-Id: I1c35600ca5437da44071dcea5361bfb42f6b72a3
This commit is contained in:
@@ -161,7 +161,7 @@ class HTTPClient(object):
|
||||
self.project_domain_id = self.auth_ref.project_domain_id
|
||||
self.auth_url = self.auth_ref.auth_url[0]
|
||||
self._management_url = self.auth_ref.management_url[0]
|
||||
self.auth_token = self.auth_ref.auth_token
|
||||
self.auth_token_from_user = self.auth_ref.auth_token
|
||||
self.trust_id = self.auth_ref.trust_id
|
||||
if self.auth_ref.has_service_catalog():
|
||||
self.region_name = self.auth_ref.service_catalog.region_name
|
||||
@@ -223,6 +223,7 @@ class HTTPClient(object):
|
||||
self._endpoint = endpoint.rstrip('/')
|
||||
if region_name:
|
||||
self.region_name = region_name
|
||||
self._auth_token = None
|
||||
|
||||
if not session:
|
||||
verify = cacert or True
|
||||
@@ -265,20 +266,28 @@ class HTTPClient(object):
|
||||
|
||||
@property
|
||||
def auth_token(self):
|
||||
if self.auth_token_from_user:
|
||||
return self.auth_token_from_user
|
||||
if self._auth_token:
|
||||
return self._auth_token
|
||||
if self.auth_ref:
|
||||
if self.auth_ref.will_expire_soon(self.stale_duration):
|
||||
self.authenticate()
|
||||
return self.auth_ref.auth_token
|
||||
if self.auth_token_from_user:
|
||||
return self.auth_token_from_user
|
||||
|
||||
@auth_token.setter
|
||||
def auth_token(self, value):
|
||||
self.auth_token_from_user = value
|
||||
"""Override the auth_token.
|
||||
|
||||
If an application sets auth_token explicitly then it will always be
|
||||
used and override any past or future retrieved token.
|
||||
"""
|
||||
self._auth_token = value
|
||||
|
||||
@auth_token.deleter
|
||||
def auth_token(self):
|
||||
del self.auth_token_from_user
|
||||
self._auth_token = None
|
||||
self.auth_token_from_user = None
|
||||
|
||||
@property
|
||||
def service_catalog(self):
|
||||
|
@@ -18,6 +18,7 @@ import json
|
||||
import httpretty
|
||||
|
||||
from keystoneclient import exceptions
|
||||
from keystoneclient.openstack.common import jsonutils
|
||||
from keystoneclient.openstack.common import timeutils
|
||||
from keystoneclient.tests.v2_0 import utils
|
||||
from keystoneclient.v2_0 import client
|
||||
@@ -157,6 +158,27 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
self.assertFalse('serviceCatalog' in cs.service_catalog.catalog)
|
||||
self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY)
|
||||
|
||||
@httpretty.activate
|
||||
def test_auth_url_token_authentication(self):
|
||||
fake_token = 'fake_token'
|
||||
fake_url = '/fake-url'
|
||||
fake_resp = {'result': True}
|
||||
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url('GET', [fake_url], json=fake_resp,
|
||||
base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT)
|
||||
|
||||
cl = client.Client(auth_url=self.TEST_URL,
|
||||
token=fake_token)
|
||||
body = jsonutils.loads(httpretty.last_request().body)
|
||||
self.assertEqual(body['auth']['token']['id'], fake_token)
|
||||
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
self.TEST_TOKEN)
|
||||
|
||||
@httpretty.activate
|
||||
def test_authenticate_success_token_scoped(self):
|
||||
del self.TEST_REQUEST_BODY['auth']['passwordCredentials']
|
||||
@@ -206,3 +228,45 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
self.TEST_RESPONSE_DICT["access"]["token"]["id"])
|
||||
self.assertFalse('serviceCatalog' in cs.service_catalog.catalog)
|
||||
self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY)
|
||||
|
||||
@httpretty.activate
|
||||
def test_allow_override_of_auth_token(self):
|
||||
fake_url = '/fake-url'
|
||||
fake_token = 'fake_token'
|
||||
fake_resp = {'result': True}
|
||||
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url('GET', [fake_url], json=fake_resp,
|
||||
base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT)
|
||||
|
||||
cl = client.Client(username='exampleuser',
|
||||
password='password',
|
||||
tenant_name='exampleproject',
|
||||
auth_url=self.TEST_URL)
|
||||
|
||||
self.assertEqual(cl.auth_token, self.TEST_TOKEN)
|
||||
|
||||
# the token returned from the authentication will be used
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
self.TEST_TOKEN)
|
||||
|
||||
# then override that token and the new token shall be used
|
||||
cl.auth_token = fake_token
|
||||
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
fake_token)
|
||||
|
||||
# if we clear that overriden token then we fall back to the original
|
||||
del cl.auth_token
|
||||
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
self.TEST_TOKEN)
|
||||
|
@@ -31,6 +31,8 @@ class UnauthenticatedTestCase(utils.TestCase):
|
||||
|
||||
class TestCase(UnauthenticatedTestCase):
|
||||
|
||||
TEST_ADMIN_IDENTITY_ENDPOINT = "http://127.0.0.1:35357/v2.0"
|
||||
|
||||
TEST_SERVICE_CATALOG = [{
|
||||
"endpoints": [{
|
||||
"adminURL": "http://cdn.admin-nets.local:8774/v1.0",
|
||||
@@ -60,7 +62,7 @@ class TestCase(UnauthenticatedTestCase):
|
||||
"name": "glance"
|
||||
}, {
|
||||
"endpoints": [{
|
||||
"adminURL": "http://127.0.0.1:35357/v2.0",
|
||||
"adminURL": TEST_ADMIN_IDENTITY_ENDPOINT,
|
||||
"region": "RegionOne",
|
||||
"internalURL": "http://127.0.0.1:5000/v2.0",
|
||||
"publicURL": "http://127.0.0.1:5000/v2.0"
|
||||
|
@@ -15,6 +15,7 @@
|
||||
import httpretty
|
||||
|
||||
from keystoneclient import exceptions
|
||||
from keystoneclient.openstack.common import jsonutils
|
||||
from keystoneclient.tests.v3 import utils
|
||||
from keystoneclient.v3 import client
|
||||
|
||||
@@ -224,6 +225,27 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
self.assertFalse('catalog' in cs.service_catalog.catalog)
|
||||
self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY)
|
||||
|
||||
@httpretty.activate
|
||||
def test_auth_url_token_authentication(self):
|
||||
fake_token = 'fake_token'
|
||||
fake_url = '/fake-url'
|
||||
fake_resp = {'result': True}
|
||||
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url('GET', [fake_url], json=fake_resp,
|
||||
base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT)
|
||||
|
||||
cl = client.Client(auth_url=self.TEST_URL,
|
||||
token=fake_token)
|
||||
body = jsonutils.loads(httpretty.last_request().body)
|
||||
self.assertEqual(body['auth']['identity']['token']['id'], fake_token)
|
||||
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
self.TEST_TOKEN)
|
||||
|
||||
@httpretty.activate
|
||||
def test_authenticate_success_token_domain_scoped(self):
|
||||
ident = self.TEST_REQUEST_BODY['auth']['identity']
|
||||
@@ -301,3 +323,45 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
||||
self.TEST_RESPONSE_HEADERS["X-Subject-Token"])
|
||||
self.assertFalse('catalog' in cs.service_catalog.catalog)
|
||||
self.assertRequestBodyIs(json=self.TEST_REQUEST_BODY)
|
||||
|
||||
@httpretty.activate
|
||||
def test_allow_override_of_auth_token(self):
|
||||
fake_url = '/fake-url'
|
||||
fake_token = 'fake_token'
|
||||
fake_resp = {'result': True}
|
||||
|
||||
self.stub_auth(json=self.TEST_RESPONSE_DICT)
|
||||
self.stub_url('GET', [fake_url], json=fake_resp,
|
||||
base_url=self.TEST_ADMIN_IDENTITY_ENDPOINT)
|
||||
|
||||
cl = client.Client(username='exampleuser',
|
||||
password='password',
|
||||
tenant_name='exampleproject',
|
||||
auth_url=self.TEST_URL)
|
||||
|
||||
self.assertEqual(cl.auth_token, self.TEST_TOKEN)
|
||||
|
||||
# the token returned from the authentication will be used
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
self.TEST_TOKEN)
|
||||
|
||||
# then override that token and the new token shall be used
|
||||
cl.auth_token = fake_token
|
||||
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
fake_token)
|
||||
|
||||
# if we clear that overriden token then we fall back to the original
|
||||
del cl.auth_token
|
||||
|
||||
resp, body = cl.get(fake_url)
|
||||
self.assertEqual(fake_resp, body)
|
||||
|
||||
self.assertEqual(httpretty.last_request().headers.get('X-Auth-Token'),
|
||||
self.TEST_TOKEN)
|
||||
|
@@ -49,6 +49,8 @@ class UnauthenticatedTestCase(utils.TestCase):
|
||||
|
||||
class TestCase(UnauthenticatedTestCase):
|
||||
|
||||
TEST_ADMIN_IDENTITY_ENDPOINT = "http://127.0.0.1:35357/v3"
|
||||
|
||||
TEST_SERVICE_CATALOG = [{
|
||||
"endpoints": [{
|
||||
"url": "http://cdn.admin-nets.local:8774/v1.0/",
|
||||
@@ -105,7 +107,7 @@ class TestCase(UnauthenticatedTestCase):
|
||||
"region": "RegionOne",
|
||||
"interface": "internal"
|
||||
}, {
|
||||
"url": "http://127.0.0.1:35357/v3",
|
||||
"url": TEST_ADMIN_IDENTITY_ENDPOINT,
|
||||
"region": "RegionOne",
|
||||
"interface": "admin"
|
||||
}],
|
||||
|
Reference in New Issue
Block a user