зеркало из https://github.com/microsoft/azure-cli.git
creds share: do not persist several fields not used for token acquire/refresh (#217)
This commit is contained in:
Родитель
f4017f5aa7
Коммит
d2aab1bcff
|
@ -3,6 +3,7 @@ import collections
|
|||
from codecs import open as codecs_open
|
||||
import json
|
||||
import os.path
|
||||
import errno
|
||||
from msrest.authentication import BasicTokenAuthentication
|
||||
import adal
|
||||
from azure.mgmt.resource.subscriptions import (SubscriptionClient,
|
||||
|
@ -31,10 +32,16 @@ _SERVICE_PRINCIPAL = 'servicePrincipal'
|
|||
_SERVICE_PRINCIPAL_ID = 'servicePrincipalId'
|
||||
_SERVICE_PRINCIPAL_TENANT = 'servicePrincipalTenant'
|
||||
_TOKEN_ENTRY_USER_ID = 'userId'
|
||||
#This could mean real access token, or client secret of a service principal
|
||||
#This could mean either real access token, or client secret of a service principal
|
||||
#This naming is no good, but can't change because xplat-cli does so.
|
||||
_ACCESS_TOKEN = 'accessToken'
|
||||
|
||||
TOKEN_FIELDS_EXCLUDED_FROM_PERSISTENCE = ['familyName',
|
||||
'givenName',
|
||||
'isUserIdDisplayable',
|
||||
'tenantId']
|
||||
|
||||
|
||||
_AUTH_CTX_FACTORY = lambda authority, cache: adal.AuthenticationContext(authority, cache=cache)
|
||||
|
||||
def _read_file_content(file_path):
|
||||
|
@ -44,6 +51,13 @@ def _read_file_content(file_path):
|
|||
file_text = file_to_read.read()
|
||||
return file_text
|
||||
|
||||
def _delete_file(file_path):
|
||||
try:
|
||||
os.remove(file_path)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENOENT:
|
||||
raise
|
||||
|
||||
class Profile(object):
|
||||
def __init__(self, storage=None, auth_ctx_factory=None):
|
||||
self._storage = storage or ACCOUNT
|
||||
|
@ -165,6 +179,9 @@ class Profile(object):
|
|||
|
||||
self._creds_cache.remove_cached_creds(user_or_sp)
|
||||
|
||||
def logout_all(self):
|
||||
self._cache_subscriptions_to_local_storage({})
|
||||
self._creds_cache.remove_all_cached_creds()
|
||||
|
||||
def load_cached_subscriptions(self):
|
||||
return self._storage.get(_SUBSCRIPTIONS) or []
|
||||
|
@ -283,6 +300,12 @@ class CredsCache(object):
|
|||
with codecs_open(self._token_file, 'w', encoding='ascii') as cred_file:
|
||||
items = self.adal_token_cache.read_items()
|
||||
all_creds = [entry for _, entry in items]
|
||||
|
||||
#trim away useless fields (needed for cred sharing with xplat)
|
||||
for i in all_creds:
|
||||
for key in TOKEN_FIELDS_EXCLUDED_FROM_PERSISTENCE:
|
||||
i.pop(key, None)
|
||||
|
||||
all_creds.extend(self._service_principal_creds)
|
||||
cred_file.write(json.dumps(all_creds))
|
||||
self.adal_token_cache.has_state_changed = False
|
||||
|
@ -372,3 +395,7 @@ class CredsCache(object):
|
|||
|
||||
if state_changed:
|
||||
self.persist_cached_creds()
|
||||
|
||||
def remove_all_cached_creds(self):
|
||||
#we can clear file contents, but deleting it is simpler
|
||||
_delete_file(self._token_file)
|
||||
|
|
|
@ -226,6 +226,29 @@ class Test_Profile(unittest.TestCase):
|
|||
self.assertEqual(mock_read_cred_file.call_count, 1)
|
||||
self.assertEqual(mock_persist_creds.call_count, 1)
|
||||
|
||||
@mock.patch('azure.cli._profile._delete_file', autospec=True)
|
||||
def test_logout_all(self, mock_delete_cred_file):
|
||||
#setup
|
||||
storage_mock = {'subscriptions': None}
|
||||
profile = Profile(storage_mock)
|
||||
consolidated = Profile._normalize_properties(self.user1,
|
||||
[self.subscription1],
|
||||
False,
|
||||
ENV_DEFAULT)
|
||||
consolidated2 = Profile._normalize_properties(self.user2,
|
||||
[self.subscription2],
|
||||
False,
|
||||
ENV_DEFAULT)
|
||||
profile._set_subscriptions(consolidated + consolidated2)
|
||||
|
||||
self.assertEqual(2, len(storage_mock['subscriptions']))
|
||||
#action
|
||||
profile.logout_all()
|
||||
|
||||
#verify
|
||||
self.assertEqual(0, len(storage_mock['subscriptions']))
|
||||
self.assertEqual(mock_delete_cred_file.call_count, 1)
|
||||
|
||||
@mock.patch('adal.AuthenticationContext', autospec=True)
|
||||
def test_find_subscriptions_thru_username_password(self, mock_auth_context):
|
||||
mock_auth_context.acquire_token_with_username_password.return_value = self.token_entry1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from azure.cli._profile import Profile
|
||||
from azure.cli._profile import Profile
|
||||
from azure.cli.commands import CommandTable
|
||||
from azure.cli._locale import L
|
||||
from .command_tables import COMMAND_TABLES
|
||||
|
@ -32,3 +32,11 @@ def set_active_subscription(args):
|
|||
|
||||
profile = Profile()
|
||||
profile.set_active_subscription(subscription_name_or_id)
|
||||
|
||||
@command_table.command('account clear')
|
||||
@command_table.description(L('Clear all stored subscriptions. '
|
||||
'To clear individual, use "logout".'))
|
||||
def clear(_):
|
||||
profile = Profile()
|
||||
profile.logout_all()
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче