Skip to content

Commit

Permalink
support login using aad device flow
Browse files Browse the repository at this point in the history
  • Loading branch information
yugangw-msft committed Mar 19, 2016
1 parent e39267f commit 6beafec
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 30 deletions.
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ mock==1.3.0
pylint==1.5.4
six==1.10.0
vcrpy==1.7.4

#Same as: -e git+https://github.com/yugangw-msft/azure-activedirectory-library-for-python.git@device#egg=azure-activedirectory-library-for-python
http://40.112.211.51:8080/packages/adal-0.2.0.zip
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[bdist_wheel]
universal=1

[install]
[easy-install]
single-version-externally-managed=1
record=RECORD.txt
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python

#-------------------------------------------------------------------------
# Copyright (c) Microsoft. All rights reserved.
Expand Down Expand Up @@ -59,6 +59,7 @@
'azure==2.0.0rc1',
'six',
'jmespath',
'adal==0.2.0' #from internal index server.
]

with open('README.rst', 'r', encoding='utf-8') as f:
Expand Down
4 changes: 3 additions & 1 deletion src/azure/cli/commands/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ def list_subscriptions(args, unexpected): #pylint: disable=unused-argument

@command('account set')
@description(L('Set the current subscription'))
@option('--subscription-id -n <subscription-id>', L('Subscription Id, unique name also works.'))
@option('--subscription-id -n <subscription-id>',
L('Subscription Id, unique name also works.'),
required=True)
def set_active_subscription(args, unexpected): #pylint: disable=unused-argument
subscription_id = args.get('subscription-id')
if not id:
Expand Down
71 changes: 44 additions & 27 deletions src/azure/cli/commands/login.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,61 @@
from msrestazure.azure_active_directory import UserPassCredentials, ServicePrincipalCredentials
from __future__ import print_function
from msrest.authentication import BasicTokenAuthentication
from adal import (acquire_token_with_username_password,
acquire_token_with_client_credentials,
acquire_user_code,
acquire_token_with_device_code)
from azure.mgmt.resource.subscriptions import (SubscriptionClient,
SubscriptionClientConfiguration)

from .._profile import Profile
from ..commands import command, description, option
from .._debug import should_disable_connection_verify
#TODO: update adal-python to support it
#from .._debug import should_disable_connection_verify
from .._locale import L

CLIENT_ID = '04b07795-8ddb-461a-bbee-02f9e1bf7b46'

@command('login')
@description(L('log in to an Azure subscription using Active Directory Organization Id'))
@option('--username -u <username>',
L('organization Id or service principal. Microsoft Account is not yet supported.'),
required=True)
L('organization Id or service principal. Microsoft Account is not yet supported.'))
@option('--password -p <password>', L('user password or client secret, will prompt if not given.'))
@option('--service-principal', L('the credential represents a service principal.'))
@option('--tenant -t <tenant>', L('the tenant associated with the service principal.'))
def login(args, unexpected): #pylint: disable=unused-argument
interactive = False

username = args.get('username')
if username:
password = args.get('password')
if not password:
import getpass
password = getpass.getpass(L('Password: '))
else:
interactive = True

password = args.get('password')
if not password:
import getpass
password = getpass.getpass(L('Password: '))

cert_verify = not should_disable_connection_verify()
if args.get('service-principal'):
tenant = args.get('tenant')
if not tenant:
raise ValueError(L('Please supply tenant using "--tenant"'))

credentials = ServicePrincipalCredentials(username,
password,
tenant=tenant,
verify=cert_verify)
tenant = args.get('tenant')
authority = _get_authority_url(tenant)
if interactive:
user_code = acquire_user_code(authority)
print(user_code['message'])
credentials = acquire_token_with_device_code(authority, user_code)
username = credentials['userId']
else:
credentials = UserPassCredentials(username, #pylint: disable=redefined-variable-type
password,
client_id=CLIENT_ID,
verify=cert_verify)
if args.get('service-principal'):
if not tenant:
raise ValueError(L('Please supply tenant using "--tenant"'))

client = SubscriptionClient(SubscriptionClientConfiguration(credentials))
credentials = acquire_token_with_client_credentials(
authority,
username,
password)
else:
credentials = acquire_token_with_username_password(
authority,
username,
password)

token_credential = BasicTokenAuthentication({'access_token': credentials['accessToken']})
client = SubscriptionClient(SubscriptionClientConfiguration(token_credential))
subscriptions = client.subscriptions.list()

if not subscriptions:
Expand All @@ -50,6 +64,9 @@ def login(args, unexpected): #pylint: disable=unused-argument
#keep useful properties and not json serializable
profile = Profile()
consolidated = Profile.normalize_properties(username, subscriptions)
profile.set_subscriptions(consolidated, credentials.token['access_token'])
profile.set_subscriptions(consolidated, credentials['accessToken'])

return list(subscriptions)

def _get_authority_url(tenant=None):
return 'https://login.microsoftonline.com/{}'.format(tenant or 'common')

0 comments on commit 6beafec

Please sign in to comment.