Merge "Implements token expiration handling"
This commit is contained in:
		@@ -67,7 +67,6 @@ class HTTPClient(object):
 | 
			
		||||
        self.tenant_id = None
 | 
			
		||||
        self.tenant_name = None
 | 
			
		||||
        self.auth_url = None
 | 
			
		||||
        self.auth_token = None
 | 
			
		||||
        self.management_url = None
 | 
			
		||||
        if timeout is not None:
 | 
			
		||||
            self.timeout = float(timeout)
 | 
			
		||||
@@ -82,7 +81,6 @@ class HTTPClient(object):
 | 
			
		||||
            self.tenant_name = self.auth_ref.tenant_name
 | 
			
		||||
            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
 | 
			
		||||
        # allow override of the auth_ref defaults from explicit
 | 
			
		||||
        # values provided to the client
 | 
			
		||||
        if username:
 | 
			
		||||
@@ -94,7 +92,9 @@ class HTTPClient(object):
 | 
			
		||||
        if auth_url:
 | 
			
		||||
            self.auth_url = auth_url.rstrip('/')
 | 
			
		||||
        if token:
 | 
			
		||||
            self.auth_token = token
 | 
			
		||||
            self.auth_token_from_user = token
 | 
			
		||||
        else:
 | 
			
		||||
            self.auth_token_from_user = None
 | 
			
		||||
        if endpoint:
 | 
			
		||||
            self.management_url = endpoint.rstrip('/')
 | 
			
		||||
        self.password = password
 | 
			
		||||
@@ -126,6 +126,23 @@ class HTTPClient(object):
 | 
			
		||||
        self.stale_duration = stale_duration or access.STALE_TOKEN_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,
 | 
			
		||||
                     tenant_id=None, auth_url=None, token=None):
 | 
			
		||||
        """ Authenticate user.
 | 
			
		||||
@@ -165,7 +182,12 @@ class HTTPClient(object):
 | 
			
		||||
        password = password or self.password
 | 
			
		||||
        tenant_name = tenant_name or self.tenant_name
 | 
			
		||||
        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,
 | 
			
		||||
                                                                 username,
 | 
			
		||||
@@ -224,7 +246,7 @@ class HTTPClient(object):
 | 
			
		||||
                                                keyring_key)
 | 
			
		||||
                if 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
 | 
			
		||||
                        auth_ref = None
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
 
 | 
			
		||||
@@ -146,7 +146,6 @@ class Client(client.HTTPClient):
 | 
			
		||||
        # if we got a response without a service catalog, set the local
 | 
			
		||||
        # list of tenants for introspection, and leave to client user
 | 
			
		||||
        # 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.management_url is None and self.auth_ref.management_url:
 | 
			
		||||
                self.management_url = self.auth_ref.management_url[0]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,12 @@
 | 
			
		||||
import copy
 | 
			
		||||
from datetime import timedelta
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from keystoneclient.v2_0 import client
 | 
			
		||||
from keystoneclient import exceptions
 | 
			
		||||
from keystoneclient.openstack.common import timeutils
 | 
			
		||||
from tests import utils
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +16,7 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
 | 
			
		||||
        self.TEST_RESPONSE_DICT = {
 | 
			
		||||
            "access": {
 | 
			
		||||
                "token": {
 | 
			
		||||
                    "expires": "12345",
 | 
			
		||||
                    "expires": "2999-01-01T00:00:10Z",
 | 
			
		||||
                    "id": self.TEST_TOKEN,
 | 
			
		||||
                    "tenant": {
 | 
			
		||||
                        "id": self.TEST_TENANT_ID
 | 
			
		||||
@@ -40,6 +42,49 @@ class AuthenticateAgainstKeystoneTests(utils.TestCase):
 | 
			
		||||
            '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):
 | 
			
		||||
        _auth = 'auth'
 | 
			
		||||
        _cred = 'passwordCredentials'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user