Remove use of auth_token for REST API
* User username/password for each individual request * Stop using single auth_token for authorizing multiple requests. Closes-launchpad-Bug: #1302828
This commit is contained in:
@@ -49,8 +49,6 @@ class HTTPClient(object):
|
|||||||
|
|
||||||
self.times = [] # [("item", starttime, endtime), ...]
|
self.times = [] # [("item", starttime, endtime), ...]
|
||||||
|
|
||||||
self.auth_token = None
|
|
||||||
|
|
||||||
self._logger = logging.getLogger(__name__)
|
self._logger = logging.getLogger(__name__)
|
||||||
if self.http_log_debug and not self._logger.handlers:
|
if self.http_log_debug and not self._logger.handlers:
|
||||||
# Logging level is already set on the root logger
|
# Logging level is already set on the root logger
|
||||||
@@ -67,10 +65,6 @@ class HTTPClient(object):
|
|||||||
# requests within the same session can reuse TCP connections from pool
|
# requests within the same session can reuse TCP connections from pool
|
||||||
self.http = requests.Session()
|
self.http = requests.Session()
|
||||||
|
|
||||||
def unauthenticate(self):
|
|
||||||
"""Forget all of our authentication information."""
|
|
||||||
self.auth_token = None
|
|
||||||
|
|
||||||
def get_timings(self):
|
def get_timings(self):
|
||||||
return self.times
|
return self.times
|
||||||
|
|
||||||
@@ -150,39 +144,16 @@ class HTTPClient(object):
|
|||||||
return resp, body
|
return resp, body
|
||||||
|
|
||||||
def _cs_request(self, url, method, **kwargs):
|
def _cs_request(self, url, method, **kwargs):
|
||||||
if self.auth_token:
|
if method in ['GET', 'DELETE']:
|
||||||
if method in ['GET', 'DELETE']:
|
url = "%s?username=%s&password=%s" % (url, self.user,
|
||||||
url = "%s?username=%s&password=%s" % (url, self.user,
|
self.password)
|
||||||
self.password)
|
else:
|
||||||
else:
|
kwargs.setdefault('body', {}).update({'username': self.user,
|
||||||
kwargs.setdefault('body', {})['authtoken'] = self.auth_token
|
'password': self.password})
|
||||||
|
|
||||||
# Perform the request once. If we get a 401 back then it
|
resp, body = self._time_request(self.api_endpoint + url, method,
|
||||||
# might be because the auth token expired, so try to
|
**kwargs)
|
||||||
# re-authenticate and try again. If it still fails, bail.
|
return resp, body
|
||||||
try:
|
|
||||||
|
|
||||||
resp, body = self._time_request(self.api_endpoint + url, method,
|
|
||||||
**kwargs)
|
|
||||||
return resp, body
|
|
||||||
except (exceptions.Unauthorized, exceptions.BadRequest) as e:
|
|
||||||
try:
|
|
||||||
# first discard auth token, to avoid the possibly expired
|
|
||||||
# token being re-used in the re-authentication attempt
|
|
||||||
self.unauthenticate()
|
|
||||||
self.authenticate()
|
|
||||||
if method in ['GET', 'DELETE']:
|
|
||||||
url = "%s?username=%s&password=%s" % (url, self.user,
|
|
||||||
self.password)
|
|
||||||
else:
|
|
||||||
kwargs.setdefault(
|
|
||||||
'body', {})['authtoken'] = self.auth_token
|
|
||||||
|
|
||||||
resp, body = self._time_request(self.api_endpoint + url,
|
|
||||||
method, **kwargs)
|
|
||||||
return resp, body
|
|
||||||
except exceptions.Unauthorized:
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def get(self, url, **kwargs):
|
def get(self, url, **kwargs):
|
||||||
return self._cs_request(url, 'GET', **kwargs)
|
return self._cs_request(url, 'GET', **kwargs)
|
||||||
@@ -196,41 +167,6 @@ class HTTPClient(object):
|
|||||||
def delete(self, url, **kwargs):
|
def delete(self, url, **kwargs):
|
||||||
return self._cs_request(url, 'DELETE', **kwargs)
|
return self._cs_request(url, 'DELETE', **kwargs)
|
||||||
|
|
||||||
def authenticate(self):
|
|
||||||
auth_url = self.auth_url
|
|
||||||
if self.version == "v2.0": # FIXME(rk): This should be better.
|
|
||||||
self._v2_auth(auth_url)
|
|
||||||
|
|
||||||
def _v2_auth(self, url):
|
|
||||||
"""Authenticate against a v2.0 auth service."""
|
|
||||||
if self.auth_token:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
body = {"username": self.user, "password": self.password}
|
|
||||||
|
|
||||||
return self._authenticate(url, body)
|
|
||||||
|
|
||||||
def _authenticate(self, url, body, **kwargs):
|
|
||||||
"""Authenticate and extract the service catalog."""
|
|
||||||
method = "POST"
|
|
||||||
token_url = url + "/login"
|
|
||||||
|
|
||||||
# Make sure we follow redirects when trying to reach Keystone
|
|
||||||
resp, respbody = self._time_request(
|
|
||||||
token_url,
|
|
||||||
method,
|
|
||||||
body=body,
|
|
||||||
allow_redirects=True,
|
|
||||||
**kwargs)
|
|
||||||
|
|
||||||
return self._extract_auth_token(url, resp, respbody)
|
|
||||||
|
|
||||||
def _extract_auth_token(self, url, resp, body):
|
|
||||||
if resp.status_code == 200 or resp.status_code == 201:
|
|
||||||
if 'OpaqueRef' not in body:
|
|
||||||
raise exceptions.AuthorizationFailure()
|
|
||||||
self.auth_token = body
|
|
||||||
|
|
||||||
|
|
||||||
def get_client_class(version):
|
def get_client_class(version):
|
||||||
version_map = {
|
version_map = {
|
||||||
|
@@ -14,8 +14,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
import mock
|
|
||||||
|
|
||||||
import seamicroclient.client
|
import seamicroclient.client
|
||||||
from seamicroclient.tests import utils
|
from seamicroclient.tests import utils
|
||||||
import seamicroclient.v2.client
|
import seamicroclient.v2.client
|
||||||
@@ -33,10 +31,3 @@ class ClientTest(utils.TestCase):
|
|||||||
def test_get_client_class_v2(self):
|
def test_get_client_class_v2(self):
|
||||||
output = seamicroclient.client.get_client_class('2')
|
output = seamicroclient.client.get_client_class('2')
|
||||||
self.assertEqual(output, seamicroclient.v2.client.Client)
|
self.assertEqual(output, seamicroclient.v2.client.Client)
|
||||||
|
|
||||||
@mock.patch.object(seamicroclient.client.HTTPClient, 'authenticate')
|
|
||||||
def test_authenticate_call_v2(self, mock_authenticate):
|
|
||||||
cs = seamicroclient.v2.client.Client("user", "password",
|
|
||||||
auth_url="foo/v2")
|
|
||||||
cs.authenticate()
|
|
||||||
self.assertTrue(mock_authenticate.called)
|
|
||||||
|
@@ -68,7 +68,8 @@ class ClientTest(utils.TestCase):
|
|||||||
'User-Agent': 'python-seamicroclient'}
|
'User-Agent': 'python-seamicroclient'}
|
||||||
mock_request.assert_called_with(
|
mock_request.assert_called_with(
|
||||||
"GET",
|
"GET",
|
||||||
"http://example.com/hi?username=%s&password=%s" % (cl.user, cl.password),
|
"http://example.com/hi?username=%s&password=%s" % (cl.user,
|
||||||
|
cl.password),
|
||||||
headers=headers)
|
headers=headers)
|
||||||
# Automatic JSON parsing
|
# Automatic JSON parsing
|
||||||
self.assertEqual(body, {"hi": "there"})
|
self.assertEqual(body, {"hi": "there"})
|
||||||
@@ -93,16 +94,6 @@ class ClientTest(utils.TestCase):
|
|||||||
|
|
||||||
test_post_call()
|
test_post_call()
|
||||||
|
|
||||||
def test_auth_failure(self):
|
|
||||||
cl = get_client()
|
|
||||||
|
|
||||||
# response must not have x-server-management-url header
|
|
||||||
@mock.patch.object(requests.Session, "request", mock_request)
|
|
||||||
def test_auth_call():
|
|
||||||
self.assertRaises(exceptions.AuthorizationFailure, cl.authenticate)
|
|
||||||
|
|
||||||
test_auth_call()
|
|
||||||
|
|
||||||
def test_connection_refused(self):
|
def test_connection_refused(self):
|
||||||
cl = get_client()
|
cl = get_client()
|
||||||
|
|
||||||
|
@@ -12,17 +12,17 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from seamicroclient import client
|
from seamicroclient import client
|
||||||
from seamicroclient.v2 import servers
|
|
||||||
from seamicroclient.v2 import pools
|
|
||||||
from seamicroclient.v2 import volumes
|
|
||||||
from seamicroclient.v2 import disks
|
|
||||||
from seamicroclient.v2 import chassis
|
from seamicroclient.v2 import chassis
|
||||||
|
from seamicroclient.v2 import disks
|
||||||
from seamicroclient.v2 import fantrays
|
from seamicroclient.v2 import fantrays
|
||||||
from seamicroclient.v2 import interfaces
|
from seamicroclient.v2 import interfaces
|
||||||
|
from seamicroclient.v2 import pools
|
||||||
from seamicroclient.v2 import powersupplies
|
from seamicroclient.v2 import powersupplies
|
||||||
from seamicroclient.v2 import scards
|
from seamicroclient.v2 import scards
|
||||||
|
from seamicroclient.v2 import servers
|
||||||
from seamicroclient.v2 import smcards
|
from seamicroclient.v2 import smcards
|
||||||
from seamicroclient.v2 import system
|
from seamicroclient.v2 import system
|
||||||
|
from seamicroclient.v2 import volumes
|
||||||
|
|
||||||
|
|
||||||
class Client(object):
|
class Client(object):
|
||||||
|
Reference in New Issue
Block a user