Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
from json import loads
import requests


from ._utils import get_registry_by_name
from .credential import acr_credential_show

from azure.cli.core._profile import Profile
from azure.cli.core._util import CLIError
from azure.cli.core.prompting import prompt, prompt_pass, NoTTYException

def _get_login_token(login_server, only_refresh_token=True, repository=None):
'''Obtains refresh and access tokens for an AAD-enabled registry.
Expand Down Expand Up @@ -101,12 +106,51 @@ def get_login_access_token(login_server, repository=None):
_, access_token = _get_login_token(login_server, only_refresh_token, repository)
return access_token

def docker_login_to_registry(login_server):
def docker_login_to_registry(registry_name, username=None, password=None):
'''Logs in the Docker client to a registry.
:param str login_server: The registry login server URL to log in to
:param str registry_name: The name of container registry
:param str username: The username used to log into the container registry
:param str password: The password used to log into the container registry
'''
refresh_token = _get_login_refresh_token(login_server)
registry, _ = get_registry_by_name(registry_name)
login_server = registry.login_server #pylint: disable=no-member

# 1. if username was specified, verify that password was also specified
if username:
if not password:
try:
password = prompt_pass(msg='Password: ')
except NoTTYException:
raise CLIError('Please specify both username and password in non-interactive mode.')

# 2. if we don't yet have credentials, attempt to get a refresh token
if not password:
try:
username = "00000000-0000-0000-0000-000000000000"
password = _get_login_refresh_token(login_server)
except: #pylint: disable=bare-except
pass

# 3. if we still don't have credentials, attempt to get the admin credentials (if enabled)
if not password:
try:
cred = acr_credential_show(registry_name)
username = cred.username
password = cred.password
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this will work for this version. The structure has changed. Please update once you rebase.

except: #pylint: disable=bare-except
pass

# 4. if we still don't have credentials, prompt the user
if not password:
try:
username = prompt('Username: ')
password = prompt_pass(msg='Password: ')
except NoTTYException:
raise CLIError(
'Unable to authenticate using admin login credentials or admin is not enabled. ' +
'Please specify both username and password in non-interactive mode.')

call(["docker", "login",
"--username", "00000000-0000-0000-0000-000000000000",
"--password", refresh_token,
"--username", username,
"--password", password,
login_server])
Original file line number Diff line number Diff line change
Expand Up @@ -97,63 +97,6 @@ def get_access_key_by_storage_account_name(storage_account_name, resource_group_

return client.list_keys(resource_group_name, storage_account_name).keys[0].value #pylint: disable=no-member

def docker_login_to_registry(login_server):
'''Logs in the Docker client to a registry.
:param str login_server: The registry login server URL to log in to
'''
profile = Profile()
_, _, tenant = profile.get_login_credentials()
refresh = profile.get_refresh_credentials()
base_endpoint = 'https://' + login_server.rstrip('/')

challenge = requests.get(base_endpoint + '/v2/')
if challenge.status_code not in [401] or 'WWW-Authenticate' not in challenge.headers:
raise CLIError('Registry did not issue a challenge.')

authenticate = challenge.headers['WWW-Authenticate']

tokens = authenticate.split(' ', 2)
if len(tokens) < 2 or tokens[0].lower() != 'bearer':
raise CLIError('Registry does not support AAD login.')

params = {y[0]: y[1].strip('"') for y in
(x.strip().split('=', 2) for x in tokens[1].split(','))}
if 'realm' not in params or 'service' not in params:
raise CLIError('Registry does not support AAD login.')

authurl = urlparse(params['realm'])
authhost = urlunparse((authurl[0], authurl[1], '/oauth2/exchange', '', '', ''))

headers = {'Content-Type': 'application/x-www-form-urlencoded'}
if isinstance(refresh, str):
content = {
'service': params['service'],
'user_type': 'user',
'tenant': tenant,
'refresh_token': refresh
}
else:
content = {
'service': params['service'],
'user_type': 'spn',
'tenant': tenant,
'username': refresh[1],
'password': refresh[2]
}

response = requests.post(authhost, urlencode(content), headers=headers)

if response.status_code not in [200]:
raise CLIError(
"Access to registry was denied. Response code: {}".format(response.status_code))

refresh_token = loads(response.content.decode("utf-8"))["refresh_token"]

call(["docker", "login",
"--username", "00000000-0000-0000-0000-000000000000",
"--password", refresh_token,
login_server])

def arm_deploy_template(resource_group_name,
registry_name,
location,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
get_access_key_by_storage_account_name,
get_resource_group_name_by_registry_name,
arm_deploy_template,
random_storage_account_name,
get_registry_by_name
random_storage_account_name
)
from ._docker_utils import (
docker_login_to_registry
Expand Down Expand Up @@ -163,10 +162,10 @@ def acr_update_set(client,

return client.update(resource_group_name, registry_name, parameters)

def acr_login(registry_name):
def acr_login(registry_name, username=None, password=None):
'''Login to a container registry through Docker.
:param str registry_name: The name of container registry
:param str username: The username used to log into the container registry
:param str password: The password used to log into the container registry
'''
registry, _ = get_registry_by_name(registry_name)
login_server = registry.login_server #pylint: disable=no-member
docker_login_to_registry(login_server)
docker_login_to_registry(registry_name, username, password)