Ejemplo n.º 1
0
def test_multitenant_authentication_not_allowed():
    expected_tenant = "expected-tenant"
    expected_token = "***"

    def fake_check_output(command_line, **_):
        match = re.search("--tenant (.*)", command_line[-1])
        assert match is None or match[1] == expected_tenant
        return json.dumps(
            {
                "expiresOn": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
                "accessToken": expected_token,
                "subscription": "some-guid",
                "tenant": expected_token,
                "tokenType": "Bearer",
            }
        )

    credential = AzureCliCredential()
    with mock.patch(CHECK_OUTPUT, fake_check_output):
        token = credential.get_token("scope")
        assert token.token == expected_token

        with mock.patch.dict(
            "os.environ", {EnvironmentVariables.AZURE_IDENTITY_DISABLE_MULTITENANTAUTH: "true"}
        ):
            token = credential.get_token("scope", tenant_id="un" + expected_tenant)
        assert token.token == expected_token
Ejemplo n.º 2
0
 def _get_azcli_token(self, subscription: str = None) -> str:
     "retrieve token from azcli login"
     token = None
     tenant = self._authority if subscription is None else None
     self._current_authentication_method = self._current_authentication_method = AuthenticationMethod.azcli_login_subscription if subscription is not None else AuthenticationMethod.azcli_login
     try:
         from azure.identity import AzureCliCredential
         try:
             credential = AzureCliCredential()
             access_token = credential.get_token(self._resource)
             expires_datetime = datetime.fromtimestamp(
                 access_token.expires_on)
             token = {
                 'accessToken': access_token.token,
                 'expiresOn':
                 expires_datetime.strftime("%Y-%m-%d %H:%M:%S.%f"),
                 'tokenType': 'Bearer',
             }
         except:
             pass
     except [ImportError, ModuleNotFoundError]:
         raise AuthenticationError(
             "Azure CLI authentication requires 'azure-cli-core' to be installed."
         )
     except:
         pass
     logger().debug(
         f"_MyAadHelper::_get_azcli_token {'failed' if token is None else 'succeeded'} to get token - subscription: '{subscription}', tenant: '{tenant}'"
     )
     return token
Ejemplo n.º 3
0
    def _get_token(self):
        try:
            credential = AzureCliCredential()
            azureToken = credential.get_token(self.scope)
        except Exception as ex:
            raise RuntimeError(str(ex))

        return azureToken.token
    def _get_token_impl(self) -> dict:
        try:
            if self._az_auth_context is None:
                self._az_auth_context = AzureCliCredential()

            self._az_token = self._az_auth_context.get_token(self._kusto_uri)
            return {TokenConstants.AZ_TOKEN_TYPE: TokenConstants.BEARER_TYPE, TokenConstants.AZ_ACCESS_TOKEN: self._az_token.token}
        except Exception as e:
            raise KustoClientError(
                "Failed to obtain Az Cli token for '{0}'.\nPlease be sure AzCli version 2.3.0 and above is intalled.\n{1}".format(self._kusto_uri, e)
            )
Ejemplo n.º 5
0
 def __init__(self, credential=None, resource_id="https://management.azure.com/.default", **kwargs):
     """Wrap any azure-identity credential to work with SDK that needs azure.common.credentials/msrestazure.
     Default resource is ARM (syntax of endpoint v2)
     :param credential: Any azure-identity credential (DefaultAzureCredential by default)
     :param str resource_id: The scope to use to get the token (default ARM)
     """
     super(CredentialWrapper, self).__init__(None)
     self.credential = credential
     if credential is None:
         self.credential = AzureCliCredential()
     self._policy = BearerTokenCredentialPolicy(self.credential, resource_id, **kwargs)
Ejemplo n.º 6
0
def _configure_resource_group(config):
    # TODO: look at availability sets
    # https://docs.microsoft.com/en-us/azure/virtual-machines/windows/tutorial-availability-sets
    subscription_id = config["provider"].get("subscription_id")
    if subscription_id is None:
        subscription_id = get_cli_profile().get_subscription_id()
    resource_client = ResourceManagementClient(AzureCliCredential(),
                                               subscription_id)
    config["provider"]["subscription_id"] = subscription_id
    logger.info("Using subscription id: %s", subscription_id)

    assert ("resource_group" in config["provider"]
            ), "Provider config must include resource_group field"
    resource_group = config["provider"]["resource_group"]

    assert (
        "location"
        in config["provider"]), "Provider config must include location field"
    params = {"location": config["provider"]["location"]}

    if "tags" in config["provider"]:
        params["tags"] = config["provider"]["tags"]

    logger.info("Creating/Updating Resource Group: %s", resource_group)
    rg_create_or_update = get_azure_sdk_function(
        client=resource_client.resource_groups,
        function_name="create_or_update")
    rg_create_or_update(resource_group_name=resource_group, parameters=params)

    # load the template file
    current_path = Path(__file__).parent
    template_path = current_path.joinpath("azure-config-template.json")
    with open(template_path, "r") as template_fp:
        template = json.load(template_fp)

    # choose a random subnet, skipping most common value of 0
    random.seed(resource_group)
    subnet_mask = "10.{}.0.0/16".format(random.randint(1, 254))

    parameters = {
        "properties": {
            "mode": DeploymentMode.incremental,
            "template": template,
            "parameters": {
                "subnet": {
                    "value": subnet_mask
                }
            },
        }
    }

    create_or_update = get_azure_sdk_function(
        client=resource_client.deployments, function_name="create_or_update")
    create_or_update(
        resource_group_name=resource_group,
        deployment_name="ray-config",
        parameters=parameters,
    ).wait()

    return config
Ejemplo n.º 7
0
def test_not_logged_in():
    """When the CLI isn't logged in, the credential should raise CredentialUnavailableError"""

    output = "ERROR: Please run 'az login' to setup account."
    with mock.patch(CHECK_OUTPUT, raise_called_process_error(1, output)):
        with pytest.raises(CredentialUnavailableError, match=NOT_LOGGED_IN):
            AzureCliCredential().get_token("scope")
def test_not_logged_in():
    """When the CLI isn't logged in, the credential should raise an error containing the CLI's output"""

    output = "ERROR: Please run 'az login' to setup account."
    with mock.patch(CHECK_OUTPUT, raise_called_process_error(1, output)):
        with pytest.raises(ClientAuthenticationError, match=output):
            AzureCliCredential().get_token("scope")
Ejemplo n.º 9
0
def test_output(run_output):
    credential = AzureCliCredential()
    subscription_id = 'c65eaf3d-141a-4b75-9642-61a4c76ae763'
    resource_client = ResourceManagementClient(credential, subscription_id)
    assert resource_client.resource_groups.get(
        'myResourceGroup').name == run_output['something']
    print('Testing clean apply')
Ejemplo n.º 10
0
def ml_workspace_list(cmd, resource_group_name):
    subscription_id = get_subscription_id(cmd.cli_ctx)

    ml_client = MLClient(subscription_id=subscription_id,
                         resource_group_name=resource_group_name,
                         credential=AzureCliCredential())
    return ml_client.workspaces.list()
Ejemplo n.º 11
0
def ml_model_create(cmd,
                    resource_group_name,
                    workspace_name,
                    name=None,
                    version=None,
                    file=None,
                    path=None,
                    params_override=[]):
    subscription_id = get_subscription_id(cmd.cli_ctx)

    ml_client = MLClient(
        subscription_id=subscription_id,
        resource_group_name=resource_group_name,
        default_workspace_name=workspace_name,
        credential=AzureCliCredential(),
    )
    if name is not None:
        params_override.append({"name": name})
    if version is not None:
        params_override.append({"version": version})
    if path is not None:
        params_override.append({"asset_path": path})
    try:
        return ml_client.model.create_or_update(
            file=file, params_override=params_override)
    except Exception as err:
        print_error_and_exit(str(err))
Ejemplo n.º 12
0
def ml_datastore_attach_blob(
    cmd,
    resource_group_name,
    workspace_name,
    account_name,
    container_name,
    name,
    account_key=None,
    sas_token=None,
    protocol=None,
    endpoint=None,
):
    subscription_id = get_subscription_id(cmd.cli_ctx)

    ml_client = MLClient(
        subscription_id=subscription_id,
        resource_group_name=resource_group_name,
        default_workspace_name=workspace_name,
        credential=AzureCliCredential(),
    )

    return ml_client.datastores.attach_azure_blob_storage(
        name,
        container_name,
        account_name,
        account_key=account_key,
        sas_token=sas_token,
        protocol=protocol,
        endpoint=endpoint,
    )
Ejemplo n.º 13
0
class AzCliTokenProvider(CloudInfoTokenProvider):
    """AzCli Token Provider obtains a refresh token from the AzCli cache and uses it to authenticate with MSAL"""
    def __init__(self, kusto_uri: str, is_async: bool = False):
        super().__init__(kusto_uri, is_async)
        self._az_auth_context = None
        self._az_auth_context_async = None
        self._az_token = None

    @staticmethod
    def name() -> str:
        return "AzCliTokenProvider"

    def _context_impl(self) -> dict:
        return {"authority:": self.name()}

    def _init_impl(self):
        pass

    def _get_token_impl(self) -> Optional[dict]:
        try:
            if self._az_auth_context is None:
                self._az_auth_context = AzureCliCredential()

            self._az_token = self._az_auth_context.get_token(self._scopes[0])
            return {
                TokenConstants.AZ_TOKEN_TYPE: TokenConstants.BEARER_TYPE,
                TokenConstants.AZ_ACCESS_TOKEN: self._az_token.token
            }
        except Exception as e:
            raise KustoClientError(
                "Failed to obtain Az Cli token for '{0}'.\nPlease be sure AzCli version 2.3.0 and above is intalled.\n{1}"
                .format(self._kusto_uri, e))

    async def _get_token_impl_async(self) -> Optional[dict]:
        try:
            if self._az_auth_context_async is None:
                self._az_auth_context_async = AsyncAzureCliCredential()

            self._az_token = await self._az_auth_context_async.get_token(
                self._scopes[0])
            return {
                TokenConstants.AZ_TOKEN_TYPE: TokenConstants.BEARER_TYPE,
                TokenConstants.AZ_ACCESS_TOKEN: self._az_token.token
            }
        except Exception as e:
            raise KustoClientError(
                "Failed to obtain Az Cli token for '{0}'.\nPlease be sure AzCli version 2.3.0 and above is installed.\n{1}"
                .format(self._kusto_uri, e))

    def _get_token_from_cache_impl(self) -> Optional[dict]:
        if self._az_token is not None:
            # A token is considered valid if it is due to expire in no less than 10 minutes
            cur_time = time.time()
            if (self._az_token.expires_on - 600) > cur_time:
                return {
                    TokenConstants.MSAL_TOKEN_TYPE: TokenConstants.BEARER_TYPE,
                    TokenConstants.MSAL_ACCESS_TOKEN: self._az_token.token
                }

        return None
Ejemplo n.º 14
0
def test_cli_not_installed_linux():
    """The credential should raise CredentialUnavailableError when the CLI isn't installed"""

    output = "/bin/sh: 1: az: not found"
    with mock.patch(CHECK_OUTPUT, raise_called_process_error(127, output)):
        with pytest.raises(CredentialUnavailableError, match=CLI_NOT_FOUND):
            AzureCliCredential().get_token("scope")
Ejemplo n.º 15
0
def test_unexpected_error():
    """When the CLI returns an unexpected error, the credential should raise an error containing the CLI's output"""

    output = "something went wrong"
    with mock.patch(CHECK_OUTPUT, raise_called_process_error(42, output)):
        with pytest.raises(ClientAuthenticationError, match=output):
            AzureCliCredential().get_token("scope")
Ejemplo n.º 16
0
def test_cli_not_installed_windows():
    """The credential should raise CredentialUnavailableError when the CLI isn't installed"""

    output = "'az' is not recognized as an internal or external command, operable program or batch file."
    with mock.patch(CHECK_OUTPUT, raise_called_process_error(1, output)):
        with pytest.raises(CredentialUnavailableError, match=CLI_NOT_FOUND):
            AzureCliCredential().get_token("scope")
Ejemplo n.º 17
0
def azure_credentials(azure_cfg: AzureCfg, pytestconfig):
    if pytestconfig.getoption('local'):
        return AzureCliCredential()
    else:
        return ClientSecretCredential(client_id=azure_cfg.client_id,
                                      client_secret=azure_cfg.client_secret,
                                      tenant_id=azure_cfg.tenant_id)
Ejemplo n.º 18
0
def test_get_token():
    """The credential should parse the CLI's output to an AccessToken"""

    access_token = "access token"
    expected_expires_on = 1602015811
    successful_output = json.dumps({
        "expiresOn":
        datetime.fromtimestamp(expected_expires_on).strftime(
            "%Y-%m-%d %H:%M:%S.%f"),
        "accessToken":
        access_token,
        "subscription":
        "some-guid",
        "tenant":
        "some-guid",
        "tokenType":
        "Bearer",
    })

    with mock.patch(CHECK_OUTPUT, mock.Mock(return_value=successful_output)):
        token = AzureCliCredential().get_token("scope")

    assert token.token == access_token
    assert type(token.expires_on) == int
    assert token.expires_on == expected_expires_on
def create_resource_group(subID):
    credential = AzureCliCredential()

    client = ResourceManagementClient(credential, subID)

    client.resource_groups.create_or_update(resource_group_name=name,
                                            parameters={"location": location})
def test_get_token():
    """The credential should parse the CLI's output to an AccessToken"""

    access_token = "access token"
    valid_seconds = 42
    successful_output = json.dumps({
        # expiresOn is a naive datetime representing valid_seconds from the epoch
        "expiresOn":
        datetime.fromtimestamp(valid_seconds).strftime("%Y-%m-%d %H:%M:%S.%f"),
        "accessToken":
        access_token,
        "subscription":
        "some-guid",
        "tenant":
        "some-guid",
        "tokenType":
        "Bearer",
    })

    with mock.patch(CHECK_OUTPUT, mock.Mock(return_value=successful_output)):
        token = AzureCliCredential().get_token("scope")

    assert token.token == access_token
    assert type(token.expires_on) == int
    assert token.expires_on == valid_seconds
Ejemplo n.º 21
0
    def add_log_export(self) -> None:
        if not self.export_appinsights:
            logger.info("not exporting appinsights")
            return

        container_name = "app-insights"

        logger.info("adding appinsight log export")
        account_name = self.results["deploy"]["func_name"]["value"]
        key = self.results["deploy"]["func_key"]["value"]
        account_url = "https://%s.blob.core.windows.net" % account_name
        client = BlobServiceClient(account_url, credential=key)
        if container_name not in [x["name"] for x in client.list_containers()]:
            client.create_container(container_name)

        expiry = datetime.utcnow() + timedelta(days=2 * 365)

        # NOTE: as this is a long-lived SAS url, it should not be logged and only
        # used in the the later-on export_configurations.create() call
        sas = generate_container_sas(
            account_name,
            container_name,
            account_key=key,
            permission=ContainerSasPermissions(write=True),
            expiry=expiry,
        )
        url = "%s/%s?%s" % (account_url, container_name, sas)

        record_types = (
            "Requests, Event, Exceptions, Metrics, PageViews, "
            "PageViewPerformance, Rdd, PerformanceCounters, Availability")

        req = ApplicationInsightsComponentExportRequest(
            record_types=record_types,
            destination_type="Blob",
            is_enabled="true",
            destination_address=url,
        )

        credential = AzureCliCredential()
        app_insight_client = ApplicationInsightsManagementClient(
            credential,
            subscription_id=self.get_subscription_id(),
        )

        to_delete = []
        for entry in app_insight_client.export_configurations.list(
                self.resource_group, self.application_name):
            if (entry.storage_name == account_name
                    and entry.container_name == container_name):
                to_delete.append(entry.export_id)

        for export_id in to_delete:
            logger.info("replacing existing export: %s", export_id)
            app_insight_client.export_configurations.delete(
                self.resource_group, self.application_name, export_id)

        app_insight_client.export_configurations.create(
            self.resource_group, self.application_name, req)
Ejemplo n.º 22
0
    def _default_chained_credentials(self) -> ChainedTokenCredential:
        managed_identity = ManagedIdentityCredential()
        azure_cli = AzureCliCredential()
        environment = EnvironmentCredential()
        shared_token_cache = SharedTokenCacheCredential()
        interactive_browser = InteractiveBrowserCredential()

        return ChainedTokenCredential(managed_identity, azure_cli, environment, shared_token_cache, interactive_browser)
Ejemplo n.º 23
0
def get_azure_token():
    credential_chain = ChainedTokenCredential(ManagedIdentityCredential(), AzureCliCredential())
    try:
        token = credential_chain.get_token("https://monitoring.azure.com//.default")
        return token.token
    except Exception as e:
        logging.exception(f"Failed to retrieve Azure token. Reason is {type(e).__name__} {e}")
        return None
def test_timeout():
    """The credential should raise CredentialUnavailableError when the subprocess times out"""

    from subprocess import TimeoutExpired

    with mock.patch(CHECK_OUTPUT, mock.Mock(side_effect=TimeoutExpired("", 42))):
        with pytest.raises(CredentialUnavailableError):
            AzureCliCredential().get_token("scope")
Ejemplo n.º 25
0
def test_parsing_error_does_not_expose_token(output):
    """Errors during CLI output parsing shouldn't expose access tokens in that output"""

    with mock.patch(CHECK_OUTPUT, mock.Mock(return_value=output)):
        with pytest.raises(ClientAuthenticationError) as ex:
            AzureCliCredential().get_token("scope")

    assert "secret value" not in str(ex.value)
    assert "secret value" not in repr(ex.value)
Ejemplo n.º 26
0
def adf_client(adf_config):
    """Creates an DataFactoryManagementClient object"""
    if adf_config["AZ_SERVICE_PRINCIPAL_ID"] is None:
        credentials = AzureCliCredential()
    else:
        credentials = ClientSecretCredential(client_id=adf_config["AZ_SERVICE_PRINCIPAL_ID"],
                                         client_secret=adf_config["AZ_SERVICE_PRINCIPAL_SECRET"],
                                         tenant_id=adf_config["AZ_SERVICE_PRINCIPAL_TENANT_ID"])
    return DataFactoryManagementClient(credentials, adf_config["AZ_SUBSCRIPTION_ID"])
def test_subprocess_error_does_not_expose_token(output):
    """Errors from the subprocess shouldn't expose access tokens in CLI output"""

    with mock.patch(CHECK_OUTPUT, raise_called_process_error(1, output=output)):
        with pytest.raises(ClientAuthenticationError) as ex:
            AzureCliCredential().get_token("scope")

    assert "secret value" not in str(ex.value)
    assert "secret value" not in repr(ex.value)
Ejemplo n.º 28
0
def ml_compute_show(cmd, resource_group_name, workspace_name, name):
    subscription_id = get_subscription_id(cmd.cli_ctx)

    ml_client = MLClient(
        subscription_id=subscription_id,
        resource_group_name=resource_group_name,
        default_workspace_name=workspace_name,
        credential=AzureCliCredential(),
    )
    return ml_client.computes.get(name=name)
Ejemplo n.º 29
0
def ml_data_delete(cmd, resource_group_name, workspace_name, name, version):
    subscription_id = get_subscription_id(cmd.cli_ctx)

    ml_client = MLClient(
        subscription_id=subscription_id,
        resource_group_name=resource_group_name,
        default_workspace_name=workspace_name,
        credential=AzureCliCredential(),
    )
    return ml_client.data.delete(name=name, version=version)
Ejemplo n.º 30
0
def ml_data_list(cmd, resource_group_name, workspace_name, name=None):
    subscription_id = get_subscription_id(cmd.cli_ctx)

    ml_client = MLClient(
        subscription_id=subscription_id,
        resource_group_name=resource_group_name,
        default_workspace_name=workspace_name,
        credential=AzureCliCredential(),
    )
    return ml_client.data.list(name=name)