diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/linux_vscode_adapter.py b/sdk/identity/azure-identity/azure/identity/_credentials/linux_vscode_adapter.py index bfd45faeb484..d31b202678df 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/linux_vscode_adapter.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/linux_vscode_adapter.py @@ -5,23 +5,31 @@ import os import json import ctypes as ct +from .._constants import VSCODE_CREDENTIALS_SECTION def _c_str(string): return ct.c_char_p(string.encode("utf-8")) +class _SECRET_SCHEMA_ATTRIBUTE(ct.Structure): + _fields_ = [ + ("name", ct.c_char_p), + ("type", ct.c_uint), + ] + + +class _SECRET_SCHEMA(ct.Structure): + _fields_ = [ + ("name", ct.c_char_p), + ("flags", ct.c_uint), + ("attributes", _SECRET_SCHEMA_ATTRIBUTE * 2), + ] +_PSECRET_SCHEMA = ct.POINTER(_SECRET_SCHEMA) + + try: _libsecret = ct.cdll.LoadLibrary("libsecret-1.so.0") - _libsecret.secret_schema_new.argtypes = [ - ct.c_char_p, - ct.c_uint, - ct.c_char_p, - ct.c_uint, - ct.c_char_p, - ct.c_uint, - ct.c_void_p, - ] _libsecret.secret_password_lookup_sync.argtypes = [ ct.c_void_p, ct.c_void_p, @@ -33,7 +41,7 @@ def _c_str(string): ct.c_void_p, ] _libsecret.secret_password_lookup_sync.restype = ct.c_char_p - _libsecret.secret_schema_unref.argtypes = [ct.c_void_p] + _libsecret.secret_password_free.argtypes = [ct.c_char_p] except OSError: _libsecret = None @@ -58,22 +66,17 @@ def _get_refresh_token(service_name, account_name): if not _libsecret: return None - # _libsecret.secret_password_lookup_sync raises segment fault on Python 2.7 - # temporarily disable it on 2.7 - import sys - - if sys.version_info[0] < 3: - raise NotImplementedError("Not supported on Python 2.7") - - if sys.version_info >= (3, 8): - raise NotImplementedError("Not supported") - err = ct.c_int() - schema = _libsecret.secret_schema_new( - _c_str("org.freedesktop.Secret.Generic"), 2, _c_str("service"), 0, _c_str("account"), 0, None - ) + attributes = [_SECRET_SCHEMA_ATTRIBUTE(_c_str("service"), 0), _SECRET_SCHEMA_ATTRIBUTE(_c_str("account"), 0)] + pattributes = (_SECRET_SCHEMA_ATTRIBUTE * 2)(*attributes) + schema = _SECRET_SCHEMA() + pschema = _PSECRET_SCHEMA(schema) + ct.memset(pschema, 0, ct.sizeof(schema)) + schema.name = _c_str("org.freedesktop.Secret.Generic") # pylint: disable=attribute-defined-outside-init + schema.flags = 2 # pylint: disable=attribute-defined-outside-init + schema.attributes = pattributes # pylint: disable=attribute-defined-outside-init p_str = _libsecret.secret_password_lookup_sync( - schema, + pschema, None, ct.byref(err), _c_str("service"), @@ -82,7 +85,6 @@ def _get_refresh_token(service_name, account_name): _c_str(account_name), None, ) - _libsecret.secret_schema_unref(schema) if err.value == 0: return p_str.decode("utf-8") @@ -90,5 +92,9 @@ def _get_refresh_token(service_name, account_name): def get_credentials(): - # Disable linux support for further investigation - raise NotImplementedError("Not supported") + try: + environment_name = _get_user_settings() + credentials = _get_refresh_token(VSCODE_CREDENTIALS_SECTION, environment_name) + return credentials + except Exception: # pylint: disable=broad-except + return None diff --git a/sdk/identity/azure-identity/azure/identity/_credentials/vscode_credential.py b/sdk/identity/azure-identity/azure/identity/_credentials/vscode_credential.py index f2bfd660711a..c40636c24e96 100644 --- a/sdk/identity/azure-identity/azure/identity/_credentials/vscode_credential.py +++ b/sdk/identity/azure-identity/azure/identity/_credentials/vscode_credential.py @@ -52,13 +52,9 @@ def get_token(self, *scopes, **kwargs): return token if not self._refresh_token: - try: - self._refresh_token = get_credentials() - if not self._refresh_token: - raise CredentialUnavailableError(message="No Azure user is logged in to Visual Studio Code.") - except NotImplementedError: # pylint:disable=try-except-raise - raise CredentialUnavailableError(message="Not supported") - + self._refresh_token = get_credentials() + if not self._refresh_token: + raise CredentialUnavailableError(message="No Azure user is logged in to Visual Studio Code.") token = self._client.obtain_token_by_refresh_token(scopes, self._refresh_token, **kwargs) return token diff --git a/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode_credential.py b/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode_credential.py index e2fdce06f19b..fcf392421294 100644 --- a/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode_credential.py +++ b/sdk/identity/azure-identity/azure/identity/aio/_credentials/vscode_credential.py @@ -56,12 +56,9 @@ async def get_token(self, *scopes, **kwargs): return token if not self._refresh_token: - try: - self._refresh_token = get_credentials() - if not self._refresh_token: - raise CredentialUnavailableError(message="No Azure user is logged in to Visual Studio Code.") - except NotImplementedError: # pylint:disable=try-except-raise - raise CredentialUnavailableError(message="Not supported") + self._refresh_token = get_credentials() + if not self._refresh_token: + raise CredentialUnavailableError(message="No Azure user is logged in to Visual Studio Code.") token = await self._client.obtain_token_by_refresh_token(scopes, self._refresh_token, **kwargs) return token diff --git a/sdk/identity/azure-identity/tests/test_vscode_credential.py b/sdk/identity/azure-identity/tests/test_vscode_credential.py index e6dc70fffd00..a0b320410bc8 100644 --- a/sdk/identity/azure-identity/tests/test_vscode_credential.py +++ b/sdk/identity/azure-identity/tests/test_vscode_credential.py @@ -105,14 +105,9 @@ def test_no_obtain_token_if_cached(): @pytest.mark.skipif(not sys.platform.startswith("linux"), reason="This test only runs on Linux") -def test_distro(): - mock_client = mock.Mock(spec=object) - mock_client.obtain_token_by_refresh_token = mock.Mock(return_value=None) - mock_client.get_cached_access_token = mock.Mock(return_value=None) - - with pytest.raises(CredentialUnavailableError): - credential = VSCodeCredential(_client=mock_client) - token = credential.get_token("scope") +def test_segfault(): + from azure.identity._credentials.linux_vscode_adapter import _get_refresh_token + _get_refresh_token("test", "test") @pytest.mark.skipif(not sys.platform.startswith("darwin"), reason="This test only runs on MacOS") diff --git a/sdk/identity/azure-identity/tests/test_vscode_credential_async.py b/sdk/identity/azure-identity/tests/test_vscode_credential_async.py index 6bdbb430044c..1f26651d45d8 100644 --- a/sdk/identity/azure-identity/tests/test_vscode_credential_async.py +++ b/sdk/identity/azure-identity/tests/test_vscode_credential_async.py @@ -106,17 +106,3 @@ async def test_no_obtain_token_if_cached(): credential = VSCodeCredential(_client=mock_client) token = await credential.get_token("scope") assert token_by_refresh_token.call_count == 0 - - -@pytest.mark.skipif(not sys.platform.startswith("linux"), reason="This test only runs on Linux") -@pytest.mark.asyncio -async def test_distro(): - - mock_client = mock.Mock(spec=object) - token_by_refresh_token = mock.Mock(return_value=None) - mock_client.obtain_token_by_refresh_token = wrap_in_future(token_by_refresh_token) - mock_client.get_cached_access_token = mock.Mock(return_value=None) - - with pytest.raises(CredentialUnavailableError): - credential = VSCodeCredential(_client=mock_client) - token = await credential.get_token("scope") diff --git a/sdk/identity/azure-identity/tests/vscode-live/run-test.py b/sdk/identity/azure-identity/tests/vscode-live/run-test.py new file mode 100644 index 000000000000..401d2f39706c --- /dev/null +++ b/sdk/identity/azure-identity/tests/vscode-live/run-test.py @@ -0,0 +1,14 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ + +from azure.identity import VSCodeCredential + +def test_live(): + credential = VSCodeCredential() + token=credential.get_token('https://vault.azure.net/.default') + print(token) + +if __name__ == "__main__": + test_live() diff --git a/sdk/identity/azure-identity/tests/vscode-live/vscode.md b/sdk/identity/azure-identity/tests/vscode-live/vscode.md new file mode 100644 index 000000000000..8b17e9fce8cb --- /dev/null +++ b/sdk/identity/azure-identity/tests/vscode-live/vscode.md @@ -0,0 +1,25 @@ +# Testing visual studio code credential + +## Test matrix + +- Python 2.7, 3.5.3, 3.8 +- Windows, Ubuntu 18.04, Redhat Enterprise Linux 8.1, Debian 10, Mac OS + +## Test steps + +- Install Visual Studio Code from https://code.visualstudio.com/ + +- Launch Visual Studio Code and go to Extension tab. + +- Search and install Azure Storage extension + +- Go to Azure tab and log in with your credential + +- Open a terminal, install latest azure-identity by running +```python +pip install azure-identity -i https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python%40Local/pypi/simple/ +``` + +- Run run-test.py + +Expect: an access token is printed out. \ No newline at end of file