Пример #1
0
def get_azure_credentials(config):
    credentials = None
    cloud_environment = get_azure_cloud_environment(config)
    if config.UseMSI and cloud_environment:
        from msrestazure.azure_active_directory import MSIAuthentication
        credentials = MSIAuthentication(cloud_environment=cloud_environment)
    elif config.UseMSI:
        from msrestazure.azure_active_directory import MSIAuthentication
        credentials = MSIAuthentication()
    elif cloud_environment:
        from azure.identity import ClientSecretCredential
        credentials = ClientSecretCredential(
            client_id = config.ApplicationId,
            client_secret = config.ApplicationKey,
            tenant_id = config.Tenantid,
            cloud_environment=cloud_environment
        )
    else:
        from azure.identity import ClientSecretCredential
        credentials = ClientSecretCredential(
            client_id = config.ApplicationId,
            client_secret = config.ApplicationKey,
            tenant_id = config.Tenantid
        )

    return credentials
Пример #2
0
class MemoryCacheRead(PerfStressTest):
    def __init__(self, arguments):
        super().__init__(arguments)

        client_id = self.get_from_env("AZURE_CLIENT_ID")
        tenant_id = self.get_from_env("AZURE_TENANT_ID")
        secret = self.get_from_env("AZURE_CLIENT_SECRET")
        self.credential = ClientSecretCredential(tenant_id, client_id, secret)
        self.async_credential = AsyncClientSecretCredential(
            tenant_id, client_id, secret)
        self.scope = "https://vault.azure.net/.default"

    async def global_setup(self):
        """Cache an access token"""

        await super().global_setup()
        self.credential.get_token(self.scope)
        await self.async_credential.get_token(self.scope)

    def run_sync(self):
        self.credential.get_token(self.scope)

    async def run_async(self):
        await self.async_credential.get_token(self.scope)

    async def close(self):
        await self.async_credential.close()
        await super().close()
Пример #3
0
    def __init__(self):

        if os.environ.get('IS_PROD', None):
            self.credential = ClientSecretCredential(
                tenant_id=os.environ.get('tenant_id', None),
                client_id=os.environ.get('client_id', None),
                client_secret=os.environ.get('client_secret', None),
            )
            self.secret_client = SecretClient(vault_url=os.environ.get(
                'vault_url', None),
                                              credential=self.credential)
            self.key_client = KeyClient(vault_url=os.environ.get(
                'vault_url', None),
                                        credential=self.credential)
        else:
            self.credential = ClientSecretCredential(
                tenant_id=Configuration.tenant_id,
                client_id=Configuration.client_id,
                client_secret=Configuration.client_secret,
            )
            self.secret_client = SecretClient(
                vault_url=Configuration.vault_url, credential=self.credential)
            self.key_client = KeyClient(vault_url=Configuration.vault_url,
                                        credential=self.credential)
        self.key_ops = [
            "encrypt", "decrypt", "sign", "verify", "wrapKey", "unwrapKey"
        ]
def test_client_secret_credential_cache():
    expired = "this token's expired"
    now = time.time()
    expired_on = int(now - 300)
    expired_token = AccessToken(expired, expired_on)
    token_payload = {
        "access_token": expired,
        "expires_in": 0,
        "ext_expires_in": 0,
        "expires_on": expired_on,
        "not_before": now,
        "token_type": "Bearer",
        "resource": str(uuid.uuid1()),
    }

    mock_response = Mock(
        text=lambda: json.dumps(token_payload),
        headers={"content-type": "application/json"},
        status_code=200,
        content_type=["application/json"],
    )
    mock_send = Mock(return_value=mock_response)

    credential = ClientSecretCredential("client_id",
                                        "secret",
                                        tenant_id=str(uuid.uuid1()),
                                        transport=Mock(send=mock_send))
    scopes = ("https://foo.bar/.default", "https://bar.qux/.default")
    token = credential.get_token(*scopes)
    assert token == expired_token

    token = credential.get_token(*scopes)
    assert token == expired_token
    assert mock_send.call_count == 2
Пример #5
0
def test_persistent_cache_linux(mock_extensions):
    """The credential should use an unencrypted cache when encryption is unavailable and the user explicitly opts in.

    This test was written when Linux was the only platform on which encryption may not be available.
    """

    required_arguments = ("tenant-id", "client-id", "secret")

    # the credential should prefer an encrypted cache even when the user allows an unencrypted one
    ClientSecretCredential(*required_arguments,
                           enable_persistent_cache=True,
                           allow_unencrypted_cache=True)
    assert mock_extensions.PersistedTokenCache.called_with(
        mock_extensions.LibsecretPersistence)
    mock_extensions.PersistedTokenCache.reset_mock()

    # (when LibsecretPersistence's dependencies aren't available, constructing it raises ImportError)
    mock_extensions.LibsecretPersistence = Mock(side_effect=ImportError)

    # encryption unavailable, no opt in to unencrypted cache -> credential should raise
    with pytest.raises(ValueError):
        ClientSecretCredential(*required_arguments,
                               enable_persistent_cache=True)

    ClientSecretCredential(*required_arguments,
                           enable_persistent_cache=True,
                           allow_unencrypted_cache=True)
    assert mock_extensions.PersistedTokenCache.called_with(
        mock_extensions.FilePersistence)
Пример #6
0
def test_enable_persistent_cache():
    """the credential should use the persistent cache only when given enable_persistent_cache=True"""

    required_arguments = ("tenant-id", "client-id", "secret")
    persistent_cache = "azure.identity._internal.persistent_cache"

    # credential should default to an in memory cache
    raise_when_called = Mock(side_effect=Exception(
        "credential shouldn't attempt to load a persistent cache"))
    with patch(persistent_cache + "._load_persistent_cache",
               raise_when_called):
        ClientSecretCredential(*required_arguments)

        # allowing an unencrypted cache doesn't count as opting in to the persistent cache
        ClientSecretCredential(*required_arguments,
                               allow_unencrypted_cache=True)

    # keyword argument opts in to persistent cache
    with patch(persistent_cache + ".msal_extensions") as mock_extensions:
        ClientSecretCredential(*required_arguments,
                               enable_persistent_cache=True)
    assert mock_extensions.PersistedTokenCache.call_count == 1

    # opting in on an unsupported platform raises an exception
    with patch(persistent_cache + ".sys.platform", "commodore64"):
        with pytest.raises(NotImplementedError):
            ClientSecretCredential(*required_arguments,
                                   enable_persistent_cache=True)
        with pytest.raises(NotImplementedError):
            ClientSecretCredential(*required_arguments,
                                   enable_persistent_cache=True,
                                   allow_unencrypted_cache=True)
Пример #7
0
def test_no_scopes():
    """The credential should raise ValueError when get_token is called with no scopes"""

    credential = ClientSecretCredential("tenant-id", "client-id",
                                        "client-secret")
    with pytest.raises(ValueError):
        credential.get_token()
Пример #8
0
def test_regional_authority():
    """the credential should configure MSAL with a regional authority specified via kwarg or environment variable"""

    mock_confidential_client = Mock(return_value=Mock(
        acquire_token_silent_with_error=lambda *_, **__: {
            "access_token": "**",
            "expires_in": 3600
        }))

    for region in RegionalAuthority:
        mock_confidential_client.reset_mock()

        # region can be configured via environment variable
        with patch.dict(
                "os.environ",
            {EnvironmentVariables.AZURE_REGIONAL_AUTHORITY_NAME: region},
                clear=True):
            credential = ClientSecretCredential("tenant", "client-id",
                                                "secret")
        with patch("msal.ConfidentialClientApplication",
                   mock_confidential_client):
            credential.get_token("scope")

        assert mock_confidential_client.call_count == 1
        _, kwargs = mock_confidential_client.call_args
        assert kwargs["azure_region"] == region
Пример #9
0
def test_multitenant_authentication_not_allowed():
    expected_tenant = "expected-tenant"
    expected_token = "***"

    def send(request, **_):
        parsed = urlparse(request.url)
        if "/oauth2/v2.0/token" not in parsed.path:
            return get_discovery_response("https://{}/{}".format(
                parsed.netloc, expected_tenant))

        tenant = parsed.path.split("/")[1]
        token = expected_token if tenant == expected_tenant else expected_token * 2
        return mock_response(json_payload=build_aad_response(
            access_token=token))

    credential = ClientSecretCredential(expected_tenant,
                                        "client-id",
                                        "secret",
                                        transport=Mock(send=send))

    token = credential.get_token("scope")
    assert token.token == expected_token

    token = credential.get_token("scope", tenant_id=expected_tenant)
    assert token.token == expected_token

    with 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
Пример #10
0
def getAccessToken(config):
    print("Get AAD access token")
    aadTokenFile = '/home/ubuntu/aad_oauth_token.json'
    if os.name == 'nt':
        aadTokenFile = '__pycache__\\aad_oauth_token.json'
    if path.exists(aadTokenFile):
        f = open(aadTokenFile, )
        data = json.load(f)
        expireOn = data[1]
        if int(time.time()) < expireOn:
            print('Reuse existing token')
            print("Access token lifetime: " + str(data[1] - int(time.time())))
            return data[0]

    print("Get token from AzureAD")
    client = ClientSecretCredential(config["TenantId"],
                                    config["ClientId"],
                                    config["ClientSecret"],
                                    authority=config["Authority"])

    accessToken = client.get_token(config["Scopes"])

    print("Access token lifetime: " + str(accessToken[1] - int(time.time())))

    pathSaveFile = '/home/ubuntu/aad_oauth_token.json'
    if os.name == 'nt':
        pathSaveFile = '__pycache__\\aad_oauth_token.json'
    with open(pathSaveFile, 'w') as outfile:
        json.dump(accessToken, outfile)

    return accessToken.token
Пример #11
0
def test_client_secret_credential_cache():
    expired = "this token's expired"
    now = int(time.time())
    expired_on = now - 3600
    expired_token = AccessToken(expired, expired_on)
    token_payload = {
        "access_token": expired,
        "expires_in": 0,
        "ext_expires_in": 0,
        "expires_on": expired_on,
        "not_before": now,
        "token_type": "Bearer",
    }
    mock_send = Mock(return_value=mock_response(json_payload=token_payload))
    scope = "scope"

    credential = ClientSecretCredential("client_id",
                                        "secret",
                                        tenant_id="some-guid",
                                        transport=Mock(send=mock_send))

    # get_token initially returns the expired token because the credential
    # doesn't check whether tokens it receives from the service have expired
    token = credential.get_token(scope)
    assert token == expired_token

    access_token = "new token"
    token_payload["access_token"] = access_token
    token_payload["expires_on"] = now + 3600
    valid_token = AccessToken(access_token, now + 3600)

    # second call should observe the cached token has expired, and request another
    token = credential.get_token(scope)
    assert token == valid_token
    assert mock_send.call_count == 2
def test_user_agent():
    transport = msal_validating_transport(
        requests=[Request(required_headers={"User-Agent": USER_AGENT})],
        responses=[mock_response(json_payload=build_aad_response(access_token="**"))],
    )

    credential = ClientSecretCredential("tenant-id", "client-id", "client-secret", transport=transport)

    credential.get_token("scope")
Пример #13
0
def test_live_multitenant_authentication(live_service_principal):
    # first create a credential with a non-existent tenant
    credential = ClientSecretCredential(
        "...", live_service_principal["client_id"],
        live_service_principal["client_secret"])
    # then get a valid token for an actual tenant
    token = credential.get_token("https://vault.azure.net/.default",
                                 tenant_id=live_service_principal["tenant_id"])
    assert token.token
    assert token.expires_on
Пример #14
0
def test_client_secret_credential(live_identity_settings):
    credential = ClientSecretCredential(
        live_identity_settings["client_id"],
        live_identity_settings["client_secret"],
        live_identity_settings["tenant_id"],
    )
    token = credential.get_token(ARM_SCOPE)
    assert token
    assert token.token
    assert token.expires_on
Пример #15
0
    def __init__(self, arguments):
        super().__init__(arguments)

        client_id = self.get_from_env("AZURE_CLIENT_ID")
        tenant_id = self.get_from_env("AZURE_TENANT_ID")
        secret = self.get_from_env("AZURE_CLIENT_SECRET")
        self.credential = ClientSecretCredential(tenant_id, client_id, secret)
        self.async_credential = AsyncClientSecretCredential(
            tenant_id, client_id, secret)
        self.scope = "https://vault.azure.net/.default"
def test_tenant_id_validation():
    """The credential should raise ValueError when given an invalid tenant_id"""

    valid_ids = {"c878a2ab-8ef4-413b-83a0-199afb84d7fb", "contoso.onmicrosoft.com", "organizations", "common"}
    for tenant in valid_ids:
        ClientSecretCredential(tenant, "client-id", "secret")

    invalid_ids = {"", "my tenant", "my_tenant", "/", "\\", '"my-tenant"', "'my-tenant'"}
    for tenant in invalid_ids:
        with pytest.raises(ValueError):
            ClientSecretCredential(tenant, "client-id", "secret")
Пример #17
0
def get_azure_credentials(config):
    credentials = None
    cloud_environment = get_azure_cloud_environment(config)
    if config.UseMSI and cloud_environment:
        try:
            from azure.identity import ManagedIdentityCredential
            credentials = ManagedIdentityCredential(
                cloud_environment=cloud_environment)
        except ImportError:
            from msrestazure.azure_active_directory import MSIAuthentication
            credentials = MSIAuthentication(
                cloud_environment=cloud_environment)
    elif config.UseMSI:
        try:
            from azure.identity import ManagedIdentityCredential
            credentials = ManagedIdentityCredential()
        except ImportError:
            from msrestazure.azure_active_directory import MSIAuthentication
            credentials = MSIAuthentication()
    elif cloud_environment:
        try:
            # try to use new libraries ClientSecretCredential (azure.identity, based on azure.core)
            from azure.identity import ClientSecretCredential
            credentials = ClientSecretCredential(
                client_id=config.ApplicationId,
                client_secret=config.ApplicationKey,
                tenant_id=config.Tenantid,
                cloud_environment=cloud_environment)
        except ImportError:
            # use old libraries ServicePrincipalCredentials (azure.common) if new one is not available
            from azure.common.credentials import ServicePrincipalCredentials
            credentials = ServicePrincipalCredentials(
                client_id=config.ApplicationId,
                secret=config.ApplicationKey,
                tenant=config.Tenantid,
                cloud_environment=cloud_environment)
    else:
        try:
            # try to use new libraries ClientSecretCredential (azure.identity, based on azure.core)
            from azure.identity import ClientSecretCredential
            credentials = ClientSecretCredential(
                client_id=config.ApplicationId,
                client_secret=config.ApplicationKey,
                tenant_id=config.Tenantid)
        except ImportError:
            # use old libraries ServicePrincipalCredentials (azure.common) if new one is not available
            from azure.common.credentials import ServicePrincipalCredentials
            credentials = ServicePrincipalCredentials(
                client_id=config.ApplicationId,
                secret=config.ApplicationKey,
                tenant=config.Tenantid)

    return credentials
Пример #18
0
def test_token_cache():
    """the credential should default to an in memory cache, and optionally use a persistent cache"""

    with patch("azure.identity._persistent_cache.msal_extensions") as mock_msal_extensions:
        credential = ClientSecretCredential("tenant", "client-id", "secret")
        assert not mock_msal_extensions.PersistedTokenCache.called
        assert isinstance(credential._cache, TokenCache)

        ClientSecretCredential(
            "tenant", "client-id", "secret", cache_persistence_options=TokenCachePersistenceOptions()
        )
        assert mock_msal_extensions.PersistedTokenCache.call_count == 1
def test_policies_configurable():
    policy = Mock(spec_set=SansIOHTTPPolicy, on_request=Mock())

    def send(*_, **__):
        return mock_response(json_payload=build_aad_response(access_token="**"))

    credential = ClientSecretCredential(
        "tenant-id", "client-id", "client-secret", policies=[ContentDecodePolicy(), policy], transport=Mock(send=send)
    )

    credential.get_token("scope")

    assert policy.on_request.called
Пример #20
0
    def init_access_token(self,
                          ad_tenant_id: str = None,
                          sp_client_id: str = None,
                          ad_domain: str = None,
                          debug_mode: bool = False) -> str:
        """
        Initialize access token to access ygdra api.

        Parameters
        ----------
        ad_tenant_id : str
            Tenant id.
            If None (default), will parse AD_TENANT_ID environment variable.
        sp_client_id: str
            Service principal client id. 
            If None (default), will parse SP_CLIENT_ID environment variable.
        ad_domain: str
            Principal domain. 
            If None (default), will parse AD_DOMAIN environment variable.
        debug_mode: bool
            Indicates if you want output intermediate steps. False by default.
        """

        if not ad_tenant_id:
            ad_tenant_id = os.getenv('AD_TENANT_ID')
        if not sp_client_id:
            sp_client_id = os.getenv('SP_CLIENT_ID')
        if not ad_domain:
            ad_domain = os.getenv('AD_DOMAIN')

        if not ad_tenant_id:
            raise ValueError('ad_tenant_id input value is null or empty')
        if not sp_client_id:
            raise ValueError('sp_client_id input value is null or empty')
        if not ad_domain:
            raise ValueError('ad_domain input value is null or empty')

        credential = ClientSecretCredential(ad_tenant_id, sp_client_id,
                                            self.sp_client_secret)

        scope = f'https://{ad_domain}/{sp_client_id}/.default'

        if (debug_mode):
            print(f'tenantId: {ad_tenant_id}')
            print(f'clientId: {sp_client_id}')
            print(f'domain: {ad_domain}')
            print(f'scope: {scope}')

        access_token = credential.get_token(scope)
        self.token = access_token.token
        return access_token.token
def test_policies_configurable():
    policy = Mock(spec_set=SansIOHTTPPolicy, on_request=Mock())

    transport = msal_validating_transport(
        requests=[Request()], responses=[mock_response(json_payload=build_aad_response(access_token="**"))],
    )

    credential = ClientSecretCredential(
        "tenant-id", "client-id", "client-secret", policies=[ContentDecodePolicy(), policy], transport=transport
    )

    credential.get_token("scope")

    assert policy.on_request.called
def test_authority(authority):
    """the credential should accept an authority, with or without scheme, as an argument or environment variable"""

    tenant_id = "expected-tenant"
    parsed_authority = urlparse(authority)
    expected_netloc = parsed_authority.netloc or authority
    expected_authority = "https://{}/{}".format(expected_netloc, tenant_id)

    mock_ctor = Mock(
        return_value=Mock(acquire_token_silent_with_error=lambda *_, **__: {"access_token": "**", "expires_in": 42})
    )

    credential = ClientSecretCredential(tenant_id, "client-id", "secret", authority=authority)
    with patch("msal.ConfidentialClientApplication", mock_ctor):
        # must call get_token because the credential constructs the MSAL application lazily
        credential.get_token("scope")

    assert mock_ctor.call_count == 1
    _, kwargs = mock_ctor.call_args
    assert kwargs["authority"] == expected_authority
    mock_ctor.reset_mock()

    # authority can be configured via environment variable
    with patch.dict("os.environ", {EnvironmentVariables.AZURE_AUTHORITY_HOST: authority}, clear=True):
        credential = ClientSecretCredential(tenant_id, "client-id", "secret")
    with patch("msal.ConfidentialClientApplication", mock_ctor):
        credential.get_token("scope")

    assert mock_ctor.call_count == 1
    _, kwargs = mock_ctor.call_args
    assert kwargs["authority"] == expected_authority
Пример #23
0
    def authenticate_sp(self,
                        tenant_id: str = None,
                        client_id: str = None,
                        client_secret: str = None) -> Credentials:
        """
        Implements authentication for the Azure provider
        """
        try:

            # Set logging level to error for libraries as otherwise generates a lot of warnings
            logging.getLogger('adal-python').setLevel(logging.ERROR)
            logging.getLogger('msrest').setLevel(logging.ERROR)
            logging.getLogger('msrestazure.azure_active_directory').setLevel(
                logging.ERROR)
            logging.getLogger('urllib3').setLevel(logging.ERROR)
            logging.getLogger(
                'azure.core.pipeline.policies.http_logging_policy').setLevel(
                    logging.ERROR)

            arm_credentials = ClientSecretCredential(
                client_id=client_id,
                client_secret=client_secret,
                tenant_id=tenant_id,
            )

            aad_graph_credentials = ClientSecretCredential(
                client_id=client_id,
                client_secret=client_secret,
                tenant_id=tenant_id,
                resource='https://graph.windows.net',
            )

            return Credentials(
                arm_credentials,
                aad_graph_credentials,
                tenant_id=tenant_id,
                current_user=client_id,
            )

        except HttpResponseError as e:
            if ', AdalError: Unsupported wstrust endpoint version. ' \
                    'Current supported version is wstrust2005 or wstrust13.' in e.args:
                logger.error(
                    f'You are likely authenticating with a Microsoft Account. \
                    This authentication mode only supports Azure Active Directory principal authentication.\
                    {e}', )

            raise e
Пример #24
0
 def generate_async_oauth_token(self):
     from azure.identity.aio import ClientSecretCredential
     return ClientSecretCredential(
         self.settings.ACTIVE_DIRECTORY_TENANT_ID,
         self.settings.ACTIVE_DIRECTORY_APPLICATION_ID,
         self.settings.ACTIVE_DIRECTORY_APPLICATION_SECRET,
     )
Пример #25
0
def test_client_secret_credential():
    client_id = "fake-client-id"
    secret = "fake-client-secret"
    tenant_id = "fake-tenant-id"
    access_token = "***"

    transport = msal_validating_transport(
        endpoint="https://localhost/" + tenant_id,
        requests=[
            Request(url_substring=tenant_id,
                    required_data={
                        "client_id": client_id,
                        "client_secret": secret
                    })
        ],
        responses=[
            mock_response(json_payload=build_aad_response(
                access_token=access_token))
        ],
    )

    token = ClientSecretCredential(tenant_id,
                                   client_id,
                                   secret,
                                   transport=transport).get_token("scope")

    assert token.token == access_token
Пример #26
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)
Пример #27
0
    def _login(self) -> Boolean:
        """Login into MS Azure Cloud account and get usable client object(s).

        :return: Boolean True value depends on successful login operation
        """
        try:
            subscription_id: str = self.config["subscription_id"]
            self.tenant_id = self.config["tenant_id"]
            client_id = self.config["client_id"]
            client_secret = self.config["client_secret"]

            credential = ClientSecretCredential(
                tenant_id=self.tenant_id,
                client_id=client_id,
                client_secret=client_secret,
            )

            self.compute_client = ComputeManagementClient(
                credential=credential, subscription_id=subscription_id
            )
            self.resource_client = ResourceManagementClient(
                credential=credential, subscription_id=subscription_id
            )

            self.network_client = NetworkManagementClient(
                credential=credential, subscription_id=subscription_id
            )

            logging.info("logging in Microsoft Azure Cloud={}".format(self.name))

            return True
        except Error as e:
            logging.error(e)
            return False
Пример #28
0
def test_client_secret_credential():
    client_id = "fake-client-id"
    secret = "fake-client-secret"
    tenant_id = "fake-tenant-id"
    access_token = "***"

    transport = validating_transport(
        requests=[
            Request(url_substring=tenant_id,
                    required_data={
                        "client_id": client_id,
                        "client_secret": secret
                    })
        ],
        responses=[
            mock_response(
                json_payload={
                    "token_type": "Bearer",
                    "expires_in": 42,
                    "ext_expires_in": 42,
                    "access_token": access_token,
                })
        ],
    )

    token = ClientSecretCredential(client_id=client_id,
                                   secret=secret,
                                   tenant_id=tenant_id,
                                   transport=transport).get_token("scope")

    # not validating expires_on because doing so requires monkeypatching time, and this is tested elsewhere
    assert token.token == access_token
Пример #29
0
def test_client_secret_credential(live_service_principal):
    credential = ClientSecretCredential(
        live_service_principal["tenant_id"],
        live_service_principal["client_id"],
        live_service_principal["client_secret"],
    )
    get_token(credential)
Пример #30
0
def get_azure_auth(
    azure_config: AzureConfig
) -> Union[DefaultAzureCredential, ClientSecretCredential]:
    """
    Returns the authentication object for the azure.identity library,
    based on either the chosen Service Principal (if set, and if the password was found), or the
    interactive browser authentication if not all Service Principal information is available.
    :param azure_config: The object containing all Azure-related information.
    :return: An azure.identity authentication object.
    """
    secrets_handler = SecretsHandling(project_root=azure_config.project_root)
    application_key = secrets_handler.get_secret_from_environment(
        fixed_paths.SERVICE_PRINCIPAL_KEY, allow_missing=True)
    if not azure_config.tenant_id:
        raise ValueError(
            "No tenant_id field was found. Please complete the Azure setup.")
    if application_key and azure_config.application_id:
        return ClientSecretCredential(tenant_id=azure_config.tenant_id,
                                      client_id=azure_config.application_id,
                                      client_secret=application_key)

    logging.warning(
        "Unable to retrieve the key for the Service Principal authentication "
        f"(expected in environment variable '{fixed_paths.SERVICE_PRINCIPAL_KEY}' or YAML). "
        f"Switching to interactive login.")
    return DefaultAzureCredential()