azure-devops/azext_devops/dev/team/credentials.py (86 lines of code) (raw):

# coding=utf-8 # -------------------------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- from __future__ import print_function import sys from knack.log import get_logger from knack.prompting import NoTTYException, prompt_pass from knack.util import CLIError from msrest.authentication import BasicAuthentication from azext_devops.dev.common._credentials import clear_credential, set_credential from azext_devops.dev.common.services import _get_connection, get_base_url logger = get_logger(__name__) def credential_set(organization=None): """Set the credential (PAT) to use for a particular organization. Refer https://aka.ms/azure-devops-cli-auth for more information on providing PAT as input. """ token = _get_pat_token() if organization is not None: organization = get_base_url(organization) logger.info("Creating connection with personal access token.") _verify_token(organization=organization, token=token) try: set_credential(organization=organization, token=token) except Exception as ex: # pylint: disable=bare-except logger.warning("Unable to use secure credential store in this environment.") logger.warning("Please refer to alternate methods at https://aka.ms/azure-devops-cli-auth") logger.warning("using Environment variable") logger.warning("or use 'az login'") raise CLIError(ex) _check_and_set_default_organization(organization) def credential_clear(organization=None): """Clear the credential for all or a particular organization :param organization: Azure Devops organization URL. Example: https://dev.azure.com/MyOrganizationName/. If no organization is specified, all organizations will be logged out. :type organization: str """ if organization is not None: organization = get_base_url(organization) clear_credential(organization) if organization is not None: print('The credential was successfully cleared.') else: print('Logged out of all Azure DevOps organizations.') _check_and_clear_default_organization(organization) def _verify_token(organization, token): credentials = BasicAuthentication('', token) connection = _get_connection(organization, credentials) vstsDir = 'azext_devops.devops_sdk.' location_client = connection.get_client(vstsDir + 'v5_0.location.location_client.LocationClient') try: connection_data = location_client.get_connection_data() except Exception as ex2: logger.debug(ex2, exc_info=True) raise CLIError("Failed to authenticate using the supplied token.") # An organization with public project enabled will not throw any exception for invalid token. # Hence, handle anonymous user case here. if connection_data.authenticated_user.id == _ANONYMOUS_USER_ID: raise CLIError("Failed to authenticate using the supplied token.") def _get_pat_token(): try: token = prompt_pass('Token: ', confirm=False, help_string="The token (PAT) to authenticate with.") while len(token) <= 1: logger.warning('Please provide a PAT token.') logger.warning('If you are using CTRL + V to paste the token, it won\'t work ' 'on windows command prompt or powershell - ' 'https://github.com/microsoft/knack/issues/160.') logger.warning('Use right click or console menu to paste the token.') token = prompt_pass('Token: ', confirm=False, help_string="The token (PAT) to authenticate with.") except NoTTYException: logger.info("Getting PAT token in non-interactive mode.") token = sys.stdin.readline().rstrip() return token # Sets organization if the default is not set def _check_and_set_default_organization(organization): if organization is not None: from azext_devops.dev.common.config import azdevops_config from azext_devops.dev.common.const import DEFAULTS_SECTION, DEVOPS_ORGANIZATION_DEFAULT from .configure import configure current_org_default = None if azdevops_config.has_option(DEFAULTS_SECTION, DEVOPS_ORGANIZATION_DEFAULT): current_org_default = azdevops_config.get(DEFAULTS_SECTION, DEVOPS_ORGANIZATION_DEFAULT) if current_org_default is None or current_org_default == '': configure(defaults=['organization={}'.format(organization)]) logger.debug("Setting this organization as default. No default was set earlier.") else: logger.debug("Another organization is already set as default.") # Clears organization if the default is set to same def _check_and_clear_default_organization(organization): if organization is not None: from azext_devops.dev.common.config import azdevops_config from azext_devops.dev.common.const import DEFAULTS_SECTION, DEVOPS_ORGANIZATION_DEFAULT from .configure import configure current_org_default = None if azdevops_config.has_option(DEFAULTS_SECTION, DEVOPS_ORGANIZATION_DEFAULT): current_org_default = azdevops_config.get(DEFAULTS_SECTION, DEVOPS_ORGANIZATION_DEFAULT) if current_org_default == organization: configure(defaults=["organization="]) logger.debug("Resetting default organization.") else: logger.debug("Default org not reset. Different organization is set as default.") _ANONYMOUS_USER_ID = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'