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:
Rohan Kanade
2014-04-08 10:35:34 +02:00
parent 626460aa55
commit ecfec61737
4 changed files with 15 additions and 97 deletions

View File

@@ -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 = {

View File

@@ -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)

View File

@@ -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()

View File

@@ -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):