Merge "Implements token expiration handling"
This commit is contained in:
@@ -67,7 +67,6 @@ class HTTPClient(object):
|
|||||||
self.tenant_id = None
|
self.tenant_id = None
|
||||||
self.tenant_name = None
|
self.tenant_name = None
|
||||||
self.auth_url = None
|
self.auth_url = None
|
||||||
self.auth_token = None
|
|
||||||
self.management_url = None
|
self.management_url = None
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
self.timeout = float(timeout)
|
self.timeout = float(timeout)
|
||||||
@@ -82,7 +81,6 @@ class HTTPClient(object):
|
|||||||
self.tenant_name = self.auth_ref.tenant_name
|
self.tenant_name = self.auth_ref.tenant_name
|
||||||
self.auth_url = self.auth_ref.auth_url[0]
|
self.auth_url = self.auth_ref.auth_url[0]
|
||||||
self.management_url = self.auth_ref.management_url[0]
|
self.management_url = self.auth_ref.management_url[0]
|
||||||
self.auth_token = self.auth_ref.auth_token
|
|
||||||
# allow override of the auth_ref defaults from explicit
|
# allow override of the auth_ref defaults from explicit
|
||||||
# values provided to the client
|
# values provided to the client
|
||||||
if username:
|
if username:
|
||||||
@@ -94,7 +92,9 @@ class HTTPClient(object):
|
|||||||
if auth_url:
|
if auth_url:
|
||||||
self.auth_url = auth_url.rstrip('/')
|
self.auth_url = auth_url.rstrip('/')
|
||||||
if token:
|
if token:
|
||||||
self.auth_token = token
|
self.auth_token_from_user = token
|
||||||
|
else:
|
||||||
|
self.auth_token_from_user = None
|
||||||
if endpoint:
|
if endpoint:
|
||||||
self.management_url = endpoint.rstrip('/')
|
self.management_url = endpoint.rstrip('/')
|
||||||
self.password = password
|
self.password = password
|
||||||
@@ -126,6 +126,23 @@ class HTTPClient(object):
|
|||||||
self.stale_duration = stale_duration or access.STALE_TOKEN_DURATION
|
self.stale_duration = stale_duration or access.STALE_TOKEN_DURATION
|
||||||
self.stale_duration = int(self.stale_duration)
|
self.stale_duration = int(self.stale_duration)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def auth_token(self):
|
||||||
|
if self.auth_token_from_user:
|
||||||
|
return self.auth_token_from_user
|
||||||
|
if self.auth_ref:
|
||||||
|
if self.auth_ref.will_expire_soon(self.stale_duration):
|
||||||
|
self.authenticate()
|
||||||
|
return self.auth_ref.auth_token
|
||||||
|
|
||||||
|
@auth_token.setter
|
||||||
|
def auth_token(self, value):
|
||||||
|
self.auth_token_from_user = value
|
||||||
|
|
||||||
|
@auth_token.deleter
|
||||||
|
def auth_token(selef):
|
||||||
|
del self.auth_token_from_user
|
||||||
|
|
||||||
def authenticate(self, username=None, password=None, tenant_name=None,
|
def authenticate(self, username=None, password=None, tenant_name=None,
|
||||||
tenant_id=None, auth_url=None, token=None):
|
tenant_id=None, auth_url=None, token=None):
|
||||||
""" Authenticate user.
|
""" Authenticate user.
|
||||||
@@ -165,7 +182,12 @@ class HTTPClient(object):
|
|||||||
password = password or self.password
|
password = password or self.password
|
||||||
tenant_name = tenant_name or self.tenant_name
|
tenant_name = tenant_name or self.tenant_name
|
||||||
tenant_id = tenant_id or self.tenant_id
|
tenant_id = tenant_id or self.tenant_id
|
||||||
token = token or self.auth_token
|
|
||||||
|
if not token:
|
||||||
|
token = self.auth_token_from_user
|
||||||
|
if (not token and self.auth_ref
|
||||||
|
and not self.auth_ref.will_expire_soon(self.stale_duration)):
|
||||||
|
token = self.auth_ref.auth_token
|
||||||
|
|
||||||
(keyring_key, auth_ref) = self.get_auth_ref_from_keyring(auth_url,
|
(keyring_key, auth_ref) = self.get_auth_ref_from_keyring(auth_url,
|
||||||
username,
|
username,
|
||||||
@@ -224,7 +246,7 @@ class HTTPClient(object):
|
|||||||
keyring_key)
|
keyring_key)
|
||||||
if auth_ref:
|
if auth_ref:
|
||||||
auth_ref = pickle.loads(auth_ref)
|
auth_ref = pickle.loads(auth_ref)
|
||||||
if auth_ref.will_expire_soon(self.stale_duration):
|
if self.auth_ref.will_expire_soon(self.stale_duration):
|
||||||
# token has expired, don't use it
|
# token has expired, don't use it
|
||||||
auth_ref = None
|
auth_ref = None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@@ -146,7 +146,6 @@ class Client(client.HTTPClient):
|
|||||||
# if we got a response without a service catalog, set the local
|
# if we got a response without a service catalog, set the local
|
||||||
# list of tenants for introspection, and leave to client user
|
# list of tenants for introspection, and leave to client user
|
||||||
# to determine what to do. Otherwise, load up the service catalog
|
# to determine what to do. Otherwise, load up the service catalog
|
||||||
self.auth_token = self.auth_ref.auth_token
|
|
||||||
if self.auth_ref.scoped:
|
if self.auth_ref.scoped:
|
||||||
if self.management_url is None and self.auth_ref.management_url:
|
if self.management_url is None and self.auth_ref.management_url:
|
||||||
self.management_url = self.auth_ref.management_url[0]
|
self.management_url = self.auth_ref.management_url[0]
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
import copy
|
import copy
|
||||||
|
from datetime import timedelta
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from keystoneclient.v2_0 import client
|
from keystoneclient.v2_0 import client
|
||||||
from keystoneclient import exceptions
|
from keystoneclient import exceptions
|
||||||
|
from keystoneclient.openstack.common import timeutils
|
||||||
from tests import utils
|
from tests import utils
|
||||||
|
|
||||||
|
|
||||||
@@ -14,7 +16,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||||||
self.TEST_RESPONSE_DICT = {
|
self.TEST_RESPONSE_DICT = {
|
||||||
"access": {
|
"access": {
|
||||||
"token": {
|
"token": {
|
||||||
"expires": "12345",
|
"expires": "2999-01-01T00:00:10Z",
|
||||||
"id": self.TEST_TOKEN,
|
"id": self.TEST_TOKEN,
|
||||||
"tenant": {
|
"tenant": {
|
||||||
"id": self.TEST_TENANT_ID
|
"id": self.TEST_TENANT_ID
|
||||||
@@ -40,6 +42,49 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
|
|||||||
'User-Agent': 'python-keystoneclient',
|
'User-Agent': 'python-keystoneclient',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def test_authenticate_success_expired(self):
|
||||||
|
# Build an expired token
|
||||||
|
self.TEST_RESPONSE_DICT['access']['token']['expires'] = \
|
||||||
|
(timeutils.utcnow() - timedelta(1)).isoformat()
|
||||||
|
resp = utils.TestResponse({
|
||||||
|
"status_code": 200,
|
||||||
|
"text": json.dumps(self.TEST_RESPONSE_DICT),
|
||||||
|
})
|
||||||
|
|
||||||
|
kwargs = copy.copy(self.TEST_REQUEST_BASE)
|
||||||
|
kwargs['headers'] = self.TEST_REQUEST_HEADERS
|
||||||
|
kwargs['data'] = json.dumps(self.TEST_REQUEST_BODY)
|
||||||
|
requests.request('POST',
|
||||||
|
self.TEST_URL + "/tokens",
|
||||||
|
**kwargs).AndReturn((resp))
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
cs = client.Client(tenant_id=self.TEST_TENANT_ID,
|
||||||
|
auth_url=self.TEST_URL,
|
||||||
|
username=self.TEST_USER,
|
||||||
|
password=self.TEST_TOKEN)
|
||||||
|
self.assertEqual(cs.management_url,
|
||||||
|
self.TEST_RESPONSE_DICT["access"]["serviceCatalog"][3]
|
||||||
|
['endpoints'][0]["adminURL"])
|
||||||
|
|
||||||
|
# Build a new response
|
||||||
|
self.mox.ResetAll()
|
||||||
|
TEST_TOKEN = "abcdef"
|
||||||
|
self.TEST_RESPONSE_DICT['access']['token']['expires'] = \
|
||||||
|
"2999-01-01T00:00:10Z"
|
||||||
|
self.TEST_RESPONSE_DICT['access']['token']['id'] = TEST_TOKEN
|
||||||
|
|
||||||
|
resp = utils.TestResponse({
|
||||||
|
"status_code": 200,
|
||||||
|
"text": json.dumps(self.TEST_RESPONSE_DICT),
|
||||||
|
})
|
||||||
|
requests.request('POST',
|
||||||
|
self.TEST_URL + "/tokens",
|
||||||
|
**kwargs).AndReturn((resp))
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
self.assertEqual(cs.auth_token, TEST_TOKEN)
|
||||||
|
|
||||||
def test_authenticate_failure(self):
|
def test_authenticate_failure(self):
|
||||||
_auth = 'auth'
|
_auth = 'auth'
|
||||||
_cred = 'passwordCredentials'
|
_cred = 'passwordCredentials'
|
||||||
|
Reference in New Issue
Block a user