Skip to content

Commit

Permalink
Merge pull request Azure#3 from yugangw-msft/signin
Browse files Browse the repository at this point in the history
Initial code to sign user in and wire up the credentials in a sample storage command
  • Loading branch information
johanste committed Feb 19, 2016
2 parents 7dd5025 + 2612bd5 commit cf105fe
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 65 deletions.
1 change: 1 addition & 0 deletions azure-cli.pyproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
</Compile>
<Compile Include="azure\cli\_argparse.py" />
<Compile Include="azure\cli\_logging.py" />
<Compile Include="azure\cli\_profile.py" />
<Compile Include="azure\cli\_session.py">
<SubType>Code</SubType>
</Compile>
Expand Down
22 changes: 22 additions & 0 deletions src/azure/cli/_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from msrest.authentication import BasicTokenAuthentication

from .main import CONFIG

class Profile(object):

def update(self, subscriptions, access_token):
subscriptions[0]['active'] = True
CONFIG['subscriptions'] = subscriptions
CONFIG['access_token'] = access_token

def get_credentials(self):
subscriptions = CONFIG['subscriptions']
sub = [x for x in subscriptions if x['active'] == True ]
if not sub and subscriptions:
sub = subscriptions

if sub:
return (BasicTokenAuthentication({ 'access_token': CONFIG['access_token']}),
sub[0]['id'] )
else:
raise ValueError('you need to login to')
91 changes: 36 additions & 55 deletions src/azure/cli/commands/login.py
Original file line number Diff line number Diff line change
@@ -1,71 +1,52 @@
from azure.mgmt.resource.subscriptions import SubscriptionClient, \
SubscriptionClientConfiguration
from msrestazure.azure_active_directory import UserPassCredentials

from .._logging import logging
from ..main import CONFIG, SESSION
from .._profile import Profile
from .._util import TableOutput
from ..commands import command, description, option

PII_WARNING_TEXT = _(
'If you choose to continue, Azure command-line interface will cache your '
'authentication information. Note that this sensitive information will be stored in '
'plain text on the file system of your computer at {}. Ensure that you take suitable '
'precautions to protect your computer from unauthorized access in order to minimize the '
'risk of that information being disclosed.'
'\nDo you wish to continue: (y/n) '
)
CLIENT_ID = '04b07795-8ddb-461a-bbee-02f9e1bf7b46'

@command('login')
@description('logs you in')
@option('--username -u <username>', _('user name or service principal ID. If multifactor authentication is required, '
'you will be prompted to use the login command without parameters for '
'interactive support.'))
@option('--environment -e <environment>', _('Environment to authenticate against, such as AzureChinaCloud; '
'must support active directory.'))
@option('--password -p <password>', _('user password or service principal secret, will prompt if not given.'))
@option('--service-principal', _('If given, log in as a service principal rather than a user.'))
@option('--certificate-file <certificateFile>', _('A PEM encoded certificate private key file.'))
@option('--thumbprint <thumbprint>', _('A hex encoded thumbprint of the certificate.'))
@option('--tenant <tenant>', _('Tenant domain or ID to log into.'))
@option('--quiet -q', _('do not prompt for confirmation of PII storage.'))
@description('log in to an Azure subscription using Active Directory Organization Id')
@option('--username -u <username>', _('organization Id. Microsoft Account is not yet supported.'))
@option('--password -p <password>', _('user password, will prompt if not given.'))
def login(args, unexpected):
username = args.get('username')
interactive = bool(username)

environment_name = args.get('environment') or 'AzureCloud'
environment = CONFIG['environments'].get(environment_name)
if not environment:
raise RuntimeError(_('Unknown environment {0}').format(environment_name))

tenant = args.get('tenant')
if args.get('service-principal') and not tenant:
tenant = input(_('Tenant: '))

# TODO: PII warning

password = args.get('password')
require_password = not args.get('service-principal') or not args.get('certificate-file')
if not interactive and require_password and not password:
if not password:
import getpass
password = getpass.getpass(_('Password: '))

if not require_password:
password = {
'certificateFile': args['certificate-file'],
'thumbprint': args.thumbprint,
}
credentials = UserPassCredentials(username, password, client_id=CLIENT_ID)
client = SubscriptionClient(SubscriptionClientConfiguration(credentials))
subscriptions = client.subscriptions.list()

if not interactive:
# TODO: Remove cached token
SESSION.pop(username + '_token', None)

# TODO: Perform login
token = ''

SESSION[username + '_token'] = token

# TODO: Get subscriptions
subscriptions = ['not-a-real-subscription']
if not subscriptions:
raise RuntimeError(_("No subscriptions found for this account"))

active_subscription = subscriptions[0]

logging.info(_('Setting subscription %s as default'), active_subscription)
SESSION['active_subscription'] = active_subscription
#keep useful properties and not json serializable
consolidated = []
for s in subscriptions:
subscription = {};
subscription['id'] = s.id.split('/')[-1]
subscription['name'] = s.display_name
subscription['state'] = s.state
subscription['user'] = username
consolidated.append(subscription)

profile = Profile()
profile.update(consolidated, credentials.token['access_token'])

#TODO, replace with JSON display
with TableOutput() as to:
for subscription in consolidated:
to.cell('Name', subscription['name'])
to.cell('Active', bool(subscription['active']))
to.cell('User', subscription['user'])
to.cell('Subscription Id', subscription['id'])
to.cell('State', subscription['state'])
to.end_row()
15 changes: 5 additions & 10 deletions src/azure/cli/commands/storage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from ..main import CONFIG, SESSION
from ..main import CONFIG, SESSION
from .._logging import logging
from .._util import TableOutput
from ..commands import command, description, option
from .._profile import Profile

@command('storage account list')
@description('List storage accounts')
Expand All @@ -11,17 +12,11 @@ def list_accounts(args, unexpected):
from azure.mgmt.storage import StorageManagementClient, StorageManagementClientConfiguration
from azure.mgmt.storage.models import StorageAccount
from msrestazure.azure_active_directory import UserPassCredentials

username = '' # TODO: get username somehow
password = '' # TODO: get password somehow

logging.code('''smc = StorageManagementClient(StorageManagementClientConfiguration(
credentials=UserPassCredentials(%r, %r),
subscription_id=%r
)''', username, password, args.subscription)
profile = Profile()
#credentials, subscription_id = profile.get_credentials()
smc = StorageManagementClient(StorageManagementClientConfiguration(
credentials=UserPassCredentials(username, password),
subscription_id=args.subscription,
*profile.get_credentials(),
))

group = args.get('resource-group')
Expand Down

0 comments on commit cf105fe

Please sign in to comment.