Пример #1
0
    def __init__(self, vault_url, credential=None):
        '''
        
        Parameters:
        
            vault_url (str) – RL of the vault the client will access. This is also called the vault's "DNS Name".
            credential (str) –  An object which can provide an access token for the vault, such as a service principal credential
            
        Example:
        
        .. code-block:: python
            
            import pynomial as pyn
            
            client = pyn.KeyVaultclient(vault_url='https://keyvaulttestinstance.vault.azure.net/')
            retrieved_secret = client.get_secret('MyPassword')
            retrieved_secret.value


        .. code-block:: python
            
            import pynomial as pyn

            credential = pyn.SPCredential()
            client = pyn.KeyVaultclient(vault_url='https://keyvaulttestinstance.vault.azure.net/', credential=credential)
            retrieved_secret = client.get_secret('MyPassword').value
            
        '''
        from azure.identity import InteractiveBrowserCredential

        if credential is None:
            credential = InteractiveBrowserCredential()
            self.token = credential.get_token()

        self = super().__init__(vault_url=vault_url, credential=credential)
Пример #2
0
def test_login_hint():
    expected_username = "******"
    auth_code_response = {"code": "authorization-code", "state": ["..."]}
    server_class = Mock(return_value=Mock(
        wait_for_redirect=lambda: auth_code_response))
    transport = Mock(send=Mock(side_effect=Exception(
        "this test mocks MSAL, so no request should be sent")))

    msal_acquire_token_result = dict(
        build_aad_response(access_token="**", id_token=build_id_token()),
        id_token_claims=id_token_claims("issuer",
                                        "subject",
                                        "audience",
                                        upn="upn"),
    )
    mock_msal_app = Mock(
        acquire_token_by_auth_code_flow=Mock(
            return_value=msal_acquire_token_result),
        initiate_auth_code_flow=Mock(
            return_value={"auth_uri": "http://localhost"}),
    )

    credential = InteractiveBrowserCredential(_server_class=server_class,
                                              transport=transport,
                                              login_hint=expected_username)
    with patch("msal.PublicClientApplication",
               Mock(return_value=mock_msal_app)):
        with patch(WEBBROWSER_OPEN, lambda _: True):
            credential.authenticate(scopes=["scope"])

    assert mock_msal_app.initiate_auth_code_flow.call_count == 1
    _, kwargs = mock_msal_app.initiate_auth_code_flow.call_args
    assert kwargs["login_hint"] == expected_username
def test_no_browser():
    transport = validating_transport(requests=[Request()] * 2, responses=[get_discovery_response()] * 2)
    credential = InteractiveBrowserCredential(
        client_id="client-id", server_class=Mock(), transport=transport, _cache=TokenCache()
    )
    with pytest.raises(ClientAuthenticationError, match=r".*browser.*"):
        credential.get_token("scope")
def test_policies_configurable():
    policy = Mock(spec_set=SansIOHTTPPolicy, on_request=Mock())
    client_id = "client-id"
    transport = validating_transport(
        requests=[Request()] * 2,
        responses=[
            get_discovery_response(),
            mock_response(json_payload=build_aad_response(
                access_token="**", id_token=build_id_token(aud=client_id))),
        ],
    )

    # mock local server fakes successful authentication by immediately returning a well-formed response
    oauth_state = "oauth-state"
    auth_code_response = {"code": "authorization-code", "state": [oauth_state]}
    server_class = Mock(return_value=Mock(
        wait_for_redirect=lambda: auth_code_response))

    credential = InteractiveBrowserCredential(policies=[policy],
                                              client_id=client_id,
                                              transport=transport,
                                              _server_class=server_class,
                                              _cache=TokenCache())

    with patch("azure.identity._credentials.browser.uuid.uuid4",
               lambda: oauth_state):
        credential.get_token("scope")

    assert policy.on_request.called
def test_user_agent():
    client_id = "client-id"
    transport = validating_transport(
        requests=[
            Request(),
            Request(required_headers={"User-Agent": USER_AGENT})
        ],
        responses=[
            get_discovery_response(),
            mock_response(json_payload=build_aad_response(
                access_token="**", id_token=build_id_token(aud=client_id))),
        ],
    )

    # mock local server fakes successful authentication by immediately returning a well-formed response
    oauth_state = "oauth-state"
    auth_code_response = {"code": "authorization-code", "state": [oauth_state]}
    server_class = Mock(return_value=Mock(
        wait_for_redirect=lambda: auth_code_response))

    credential = InteractiveBrowserCredential(client_id=client_id,
                                              transport=transport,
                                              _server_class=server_class,
                                              _cache=TokenCache())

    with patch("azure.identity._credentials.browser.uuid.uuid4",
               lambda: oauth_state):
        credential.get_token("scope")
def test_timeout():
    """get_token should raise ClientAuthenticationError when the server times out without receiving a redirect"""

    timeout = 0.01

    class GuaranteedTimeout(AuthCodeRedirectServer, object):
        def handle_request(self):
            time.sleep(timeout + 0.01)
            super(GuaranteedTimeout, self).handle_request()

    # mock transport handles MSAL's tenant discovery
    transport = Mock(send=lambda _, **__: mock_response(
        json_payload={
            "authorization_endpoint": "https://a/b",
            "token_endpoint": "https://a/b"
        }))

    credential = InteractiveBrowserCredential(timeout=timeout,
                                              transport=transport,
                                              _cache=TokenCache(),
                                              _server_class=GuaranteedTimeout)

    with patch(WEBBROWSER_OPEN, lambda _: True):
        with pytest.raises(ClientAuthenticationError) as ex:
            credential.get_token("scope")
    assert "timed out" in ex.value.message.lower()
def test_cannot_bind_port():
    """get_token should raise CredentialUnavailableError when the redirect listener can't bind a port"""

    credential = InteractiveBrowserCredential(_server_class=Mock(
        side_effect=socket.error))
    with pytest.raises(CredentialUnavailableError):
        credential.get_token("scope")
Пример #8
0
def test_interactive_credential_timeout():
    # mock transport handles MSAL's tenant discovery
    transport = Mock(send=lambda _, **__: mock_response(
        json_payload={
            "authorization_endpoint": "https://a/b",
            "token_endpoint": "https://a/b"
        }))

    # mock local server blocks long enough to exceed the timeout
    timeout = 0.01
    server_instance = Mock(
        wait_for_redirect=functools.partial(time.sleep, timeout + 0.01))
    server_class = Mock(return_value=server_instance)

    credential = InteractiveBrowserCredential(
        client_id="guid",
        client_secret="secret",
        server_class=server_class,
        timeout=timeout,
        transport=transport,
        instance_discovery=
        False,  # kwargs are passed to MSAL; this one prevents an AAD verification request
    )

    with pytest.raises(ClientAuthenticationError) as ex:
        credential.get_token("scope")
    assert "timed out" in ex.value.message.lower()
Пример #9
0
    def get_credential(self,
                       auth_record=None,
                       user_client_id=None,
                       tenant_id=None) -> InteractiveBrowserCredential:
        '''
        Raises
        ------
        ValueError
            If PyGObject is not installed in the host Linux OS.
        '''
        profile = read_profile()
        user_cloud = profile.get('cloud', None)
        cloud_authority = user_cloud.get('azure_ad_endpoint', None)

        authority = cloud_authority or DEFAULT_AUTHORITY
        client_id = user_client_id or DEFAULT_CLIENT_ID

        # Once a user is authenticated they get an auth_record object which will have the authority and client_id
        # therefore we don't need to pass authority and client_id to InteractiveBrowserCredential.
        if auth_record:
            return InteractiveBrowserCredential(
                enable_persistent_cache=True,
                allow_unencrypted_cache=False,
                authentication_record=auth_record,
            )

        # Passes authority and client_id when the user doesn't have an auth record
        return InteractiveBrowserCredential(
            authority=authority,
            client_id=client_id,
            tenant_id=tenant_id,
            enable_persistent_cache=True,
            allow_unencrypted_cache=False,
        )
def test_disable_automatic_authentication():
    """When configured for strict silent auth, the credential should raise when silent auth fails"""

    transport = Mock(send=Mock(side_effect=Exception("no request should be sent")))
    credential = InteractiveBrowserCredential(disable_automatic_authentication=True, transport=transport)

    with patch(WEBBROWSER_OPEN, Mock(side_effect=Exception("credential shouldn't try interactive authentication"))):
        with pytest.raises(AuthenticationRequiredError):
            credential.get_token("scope")
def test_cannot_bind_redirect_uri():
    """When a user specifies a redirect URI, the credential shouldn't attempt to bind another"""

    server = Mock(side_effect=socket.error)
    credential = InteractiveBrowserCredential(redirect_uri="http://localhost:42", _server_class=server)

    with pytest.raises(CredentialUnavailableError):
        credential.get_token("scope")

    server.assert_called_once_with("localhost", 42, timeout=ANY)
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:
        InteractiveBrowserCredential(tenant_id=tenant)

    invalid_ids = {"my tenant", "my_tenant", "/", "\\", '"my-tenant"', "'my-tenant'"}
    for tenant in invalid_ids:
        with pytest.raises(ValueError):
            InteractiveBrowserCredential(tenant_id=tenant)
def test_policies_configurable():
    # the policy raises an exception so this test can run without authenticating i.e. opening a browser
    expected_message = "test_policies_configurable"
    policy = Mock(spec_set=SansIOHTTPPolicy, on_request=Mock(side_effect=Exception(expected_message)))

    credential = InteractiveBrowserCredential(policies=[policy])

    with pytest.raises(ClientAuthenticationError) as ex:
        credential.get_token("scope")

    assert expected_message in ex.value.message
    assert policy.on_request.called
def test_no_browser():
    """The credential should raise CredentialUnavailableError when it can't open a browser"""

    transport = validating_transport(requests=[Request()] * 2,
                                     responses=[get_discovery_response()] * 2)
    credential = InteractiveBrowserCredential(client_id="client-id",
                                              _server_class=Mock(),
                                              transport=transport)
    with patch(InteractiveBrowserCredential.__module__ + "._open_browser",
               lambda _: False):
        with pytest.raises(CredentialUnavailableError, match=r".*browser.*"):
            credential.get_token("scope")
def test_authenticate():
    client_id = "client-id"
    environment = "localhost"
    issuer = "https://" + environment
    tenant_id = "some-tenant"
    authority = issuer + "/" + tenant_id

    access_token = "***"
    scope = "scope"

    # mock AAD response with id token
    object_id = "object-id"
    home_tenant = "home-tenant-id"
    username = "******"
    id_token = build_id_token(aud=client_id, iss=issuer, object_id=object_id, tenant_id=home_tenant, username=username)
    auth_response = build_aad_response(
        uid=object_id, utid=home_tenant, access_token=access_token, refresh_token="**", id_token=id_token
    )

    transport = validating_transport(
        requests=[Request(url_substring=issuer)] * 3,
        responses=[get_discovery_response(authority)] * 2 + [mock_response(json_payload=auth_response)],
    )

    # mock local server fakes successful authentication by immediately returning a well-formed response
    oauth_state = "state"
    auth_code_response = {"code": "authorization-code", "state": [oauth_state]}
    server_class = Mock(return_value=Mock(wait_for_redirect=lambda: auth_code_response))

    with patch(InteractiveBrowserCredential.__module__ + ".uuid.uuid4", lambda: oauth_state):
        with patch(WEBBROWSER_OPEN, lambda _: True):
            credential = InteractiveBrowserCredential(
                _cache=TokenCache(),
                authority=environment,
                client_id=client_id,
                server_class=server_class,
                tenant_id=tenant_id,
                transport=transport,
            )
            record = credential._authenticate(scopes=(scope,))

    assert record.authority == environment
    assert record.home_account_id == object_id + "." + home_tenant
    assert record.tenant_id == home_tenant
    assert record.username == username

    # credential should have a cached access token for the scope used in authenticate
    with patch(WEBBROWSER_OPEN, Mock(side_effect=Exception("credential should authenticate silently"))):
        token = credential.get_token(scope)
    assert token.token == access_token
def test_browser_credential():
    transport = Mock(wraps=RequestsTransport())
    credential = InteractiveBrowserCredential(transport=transport)
    scope = "https://management.azure.com/.default"  # N.B. this is valid only in Public Cloud

    record = credential.authenticate(scopes=(scope, ))
    assert record.authority
    assert record.home_account_id
    assert record.tenant_id
    assert record.username

    # credential should have a cached access token for the scope used in authenticate
    with patch(
            WEBBROWSER_OPEN,
            Mock(side_effect=Exception(
                "credential should authenticate silently"))):
        token = credential.get_token(scope)
    assert token.token

    credential = InteractiveBrowserCredential(transport=transport)
    token = credential.get_token(scope)
    assert token.token

    with patch(
            WEBBROWSER_OPEN,
            Mock(side_effect=Exception(
                "credential should authenticate silently"))):
        second_token = credential.get_token(scope)
    assert second_token.token == token.token

    # every request should have the correct User-Agent
    for call in transport.send.call_args_list:
        args, _ = call
        request = args[0]
        assert request.headers["User-Agent"] == USER_AGENT
def test_redirect_uri():
    """The credential should configure the redirect server to use a given redirect_uri"""

    expected_hostname = "localhost"
    expected_port = 42424
    expected_message = "test_redirect_uri"
    server = Mock(side_effect=Exception(expected_message))  # exception prevents this test actually authenticating
    credential = InteractiveBrowserCredential(
        redirect_uri="htps://{}:{}".format(expected_hostname, expected_port), _server_class=server
    )
    with pytest.raises(ClientAuthenticationError) as ex:
        credential.get_token("scope")

    assert expected_message in ex.value.message
    server.assert_called_once_with(expected_hostname, expected_port, timeout=ANY)
Пример #18
0
def test_no_browser():
    discovery_response = mock_response(
        json_payload={
            name: "https://foo/bar"
            for name in ("authorization_endpoint", "token_endpoint",
                         "tenant_discovery_endpoint")
        })
    transport = validating_transport(
        requests=[Request()] * 2,
        responses=[discovery_response, discovery_response])
    credential = InteractiveBrowserCredential(client_id="client-id",
                                              client_secret="secret",
                                              server_class=Mock(),
                                              transport=transport)
    with pytest.raises(ClientAuthenticationError, match=r".*browser.*"):
        credential.get_token("scope")
def test_wsl_fallback(uname, is_wsl):
    """the credential should invoke powershell.exe to open a browser in WSL when webbrowser.open fails"""

    auth_uri = "http://localhost"
    expected_access_token = "**"
    msal_acquire_token_result = dict(
        build_aad_response(access_token=expected_access_token,
                           id_token=build_id_token()),
        id_token_claims=id_token_claims("issuer",
                                        "subject",
                                        "audience",
                                        upn="upn"),
    )
    msal_app = Mock(
        initiate_auth_code_flow=Mock(return_value={"auth_uri": auth_uri}),
        acquire_token_by_auth_code_flow=Mock(
            return_value=msal_acquire_token_result),
    )

    transport = Mock(send=Mock(side_effect=Exception(
        "this test mocks MSAL, so no request should be sent")))
    credential = InteractiveBrowserCredential(_server_class=Mock(),
                                              transport=transport)

    with patch(InteractiveBrowserCredential.__module__ +
               ".subprocess.call") as subprocess_call:
        subprocess_call.return_value = 0
        with patch(InteractiveBrowserCredential.__module__ + ".platform.uname",
                   lambda: uname):
            with patch.object(InteractiveBrowserCredential, "_get_app",
                              lambda _: msal_app):
                with patch(WEBBROWSER_OPEN, lambda _: False):
                    try:
                        token = credential.get_token("scope")
                    except CredentialUnavailableError:
                        assert not is_wsl, "credential should invoke powershell.exe in WSL"
                        return

    assert is_wsl, "credential should raise CredentialUnavailableError when not in WSL"
    assert token.token == expected_access_token
    assert subprocess_call.call_count == 1
    args, kwargs = subprocess_call.call_args
    assert args[0][0] == "powershell.exe"
    assert auth_uri in args[0][-1]
    if platform.python_version() >= "3.3":
        assert "timeout" in kwargs
Пример #20
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)
Пример #21
0
def _credential(
) -> "InteractiveBrowserCredential":  # Python 3.7+ can have forward reference
    if not AZURE_CLI_INSTALLED:
        raise RuntimeError(
            "In order to use webviz deploy features, you need to first install "
            "the optional deploy dependencies. You can do this by e.g. running "
            "'pip install webviz-config[deployment]'")

    return InteractiveBrowserCredential()
def test_claims_challenge():
    """get_token and authenticate should pass any claims challenge to MSAL token acquisition APIs"""

    expected_claims = '{"access_token": {"essential": "true"}'

    auth_code_response = {"code": "authorization-code", "state": ["..."]}
    server_class = Mock(return_value=Mock(
        wait_for_redirect=lambda: auth_code_response))

    msal_acquire_token_result = dict(
        build_aad_response(access_token="**", id_token=build_id_token()),
        id_token_claims=id_token_claims("issuer",
                                        "subject",
                                        "audience",
                                        upn="upn"),
    )

    transport = Mock(send=Mock(side_effect=Exception(
        "this test mocks MSAL, so no request should be sent")))
    credential = InteractiveBrowserCredential(_server_class=server_class,
                                              transport=transport)
    with patch.object(InteractiveBrowserCredential,
                      "_get_app") as get_mock_app:
        msal_app = get_mock_app()
        msal_app.initiate_auth_code_flow.return_value = {
            "auth_uri": "http://localhost"
        }
        msal_app.acquire_token_by_auth_code_flow.return_value = msal_acquire_token_result

        with patch(WEBBROWSER_OPEN, lambda _: True):
            credential.authenticate(scopes=["scope"], claims=expected_claims)

        assert msal_app.acquire_token_by_auth_code_flow.call_count == 1
        args, kwargs = msal_app.acquire_token_by_auth_code_flow.call_args
        assert kwargs["claims_challenge"] == expected_claims

        with patch(WEBBROWSER_OPEN, lambda _: True):
            credential.get_token("scope", claims=expected_claims)

        assert msal_app.acquire_token_by_auth_code_flow.call_count == 2
        args, kwargs = msal_app.acquire_token_by_auth_code_flow.call_args
        assert kwargs["claims_challenge"] == expected_claims

        msal_app.get_accounts.return_value = [{
            "home_account_id":
            credential._auth_record.home_account_id
        }]
        msal_app.acquire_token_silent_with_error.return_value = msal_acquire_token_result
        credential.get_token("scope", claims=expected_claims)

        assert msal_app.acquire_token_silent_with_error.call_count == 1
        args, kwargs = msal_app.acquire_token_silent_with_error.call_args
        assert kwargs["claims_challenge"] == expected_claims
Пример #23
0
def test_interactive_credential():
    oauth_state = "state"
    expected_token = "access-token"

    transport = validating_transport(
        requests=[Request()] *
        2,  # not validating requests because they're formed by MSAL
        responses=[
            # expecting tenant discovery then a token request
            mock_response(
                json_payload={
                    "authorization_endpoint": "https://a/b",
                    "token_endpoint": "https://a/b"
                }),
            mock_response(
                json_payload={
                    "access_token": expected_token,
                    "expires_in": 42,
                    "token_type": "Bearer",
                    "ext_expires_in": 42,
                }),
        ],
    )

    # mock local server fakes successful authentication by immediately returning a well-formed response
    auth_code_response = {"code": "authorization-code", "state": [oauth_state]}
    server_class = Mock(return_value=Mock(
        wait_for_redirect=lambda: auth_code_response))

    credential = InteractiveBrowserCredential(
        client_id="guid",
        client_secret="secret",
        server_class=server_class,
        transport=transport,
        instance_discovery=
        False,  # kwargs are passed to MSAL; this one prevents an AAD verification request
    )

    # ensure the request beginning the flow has a known state value
    with patch("azure.identity._credentials.browser.uuid.uuid4",
               lambda: oauth_state):
        token = credential.get_token("scope")
    assert token.token == expected_token
Пример #24
0
    def _initialize_credentials(self):
        if self.subscription_id is not None \
           and self.arm_base_url is not None:
            if self.vscode_tenant_id is None:
                self.vscode_tenant_id = self._get_tenant_id(
                    arm_base_url=self.arm_base_url,
                    subscription_id=self.subscription_id)
            if self.shared_cache_tenant_id is None:
                self.shared_cache_tenant_id = self._get_tenant_id(
                    arm_base_url=self.arm_base_url,
                    subscription_id=self.subscription_id)
            if self.interactive_browser_tenant_id is None:
                self.interactive_browser_tenant_id = self._get_tenant_id(
                    arm_base_url=self.arm_base_url,
                    subscription_id=self.subscription_id)

        credentials = []  # type: List[AsyncTokenCredential]
        if not self.exclude_token_file_credential:
            credentials.append(_TokenFileCredential())
        if not self.exclude_environment_credential:
            credentials.append(EnvironmentCredential(authority=self.authority))
        if not self.exclude_managed_identity_credential:
            credentials.append(
                ManagedIdentityCredential(
                    client_id=self.managed_identity_client_id))
        if not self.exclude_shared_token_cache_credential and SharedTokenCacheCredential.supported(
        ):
            try:
                # username and/or tenant_id are only required when the cache contains tokens for multiple identities
                shared_cache = SharedTokenCacheCredential(
                    username=self.shared_cache_username,
                    tenant_id=self.shared_cache_tenant_id,
                    authority=self.authority)
                credentials.append(shared_cache)
            except Exception as ex:  # pylint:disable=broad-except
                _LOGGER.info("Shared token cache is unavailable: '%s'", ex)
        if not self.exclude_visual_studio_code_credential:
            credentials.append(
                VisualStudioCodeCredential(tenant_id=self.vscode_tenant_id))
        if not self.exclude_cli_credential:
            credentials.append(AzureCliCredential())
        if not self.exclude_powershell_credential:
            credentials.append(AzurePowerShellCredential())
        if not self.exclude_interactive_browser_credential:
            credentials.append(
                InteractiveBrowserCredential(
                    tenant_id=self.interactive_browser_tenant_id))
        if not self.exclude_device_code_credential:
            credentials.append(
                DeviceCodeCredential(
                    tenant_id=self.interactive_browser_tenant_id))

        self.credentials = credentials
Пример #25
0
def test_token_cache_persistence_options():
    with mock.patch("azure.identity._persistent_cache.msal_extensions"):
        # [START snippet]
        cache_options = TokenCachePersistenceOptions()
        credential = InteractiveBrowserCredential(
            cache_persistence_options=cache_options)

        # specify a cache name to isolate the cache from other applications
        TokenCachePersistenceOptions(name="my_application")

        # configure the cache to fall back to unencrypted storage when encryption isn't available
        TokenCachePersistenceOptions(allow_unencrypted_storage=True)
    def _get_secret_client(self):
        if self.authn_type == "device":
            authority = self.authority_uri.replace("https://", "")
            credentials = DeviceCodeCredential(
                client_id=self.settings.CLIENT_ID,
                authority=authority,
                prompt_callback=_device_code_callback,
            )
        else:
            credentials = InteractiveBrowserCredential()

        # Create a secret client
        secret_client = SecretClient(self.vault_uri, credentials)
        return secret_client
Пример #27
0
    def create_from_env(
        cls,
        account_name: str,
        file_system_name: str,
        interactive: bool = False,
        adl_secret: Optional[ADLSecret] = None,
        **kwargs,
    ) -> "ADLGen2FileSystem":
        """
        Creates ADL Gen2 file system client.

        Parameters
        ----------
        account_name: str
            Azure account name
        file_system_name: str
            Container name
        interactive: bool
            If true then use interactive authentication
        adl_secret: ADLSecret
            Azure authentication information

        Returns
        -------
        ADLGen2FileSystem
        """
        if interactive:
            logger.info("Attempting to use interactive azure authentication")
            credential = InteractiveBrowserCredential()
        else:
            if type(adl_secret) is not ADLSecret:
                raise ConfigException("Unsupported type for adl_secret '%s'" %
                                      type(adl_secret))
            adl_secret = cast(ADLSecret, adl_secret)
            logger.info("Attempting to use datalake service authentication")
            credential = ClientSecretCredential(
                tenant_id=adl_secret.tenant_id,
                client_id=adl_secret.client_id,
                client_secret=adl_secret.client_secret,
            )
        return cls.create_from_credential(account_name, file_system_name,
                                          credential, **kwargs)
Пример #28
0
import os
import sys
from azure.identity import AuthenticationRequiredError, InteractiveBrowserCredential
from azure.keyvault.secrets import SecretClient

# This sample uses Key Vault only for demonstration. Any client accepting azure-identity credentials will work the same.
VAULT_URL = os.environ.get("VAULT_URL")
if not VAULT_URL:
    print(
        "This sample expects environment variable 'VAULT_URL' to be set with the URL of a Key Vault."
    )
    sys.exit(1)

# If it's important for your application to prompt for authentication only at certain times,
# create the credential with disable_automatic_authentication=True. This configures the credential to raise
# when interactive authentication is required, instead of immediately beginning that authentication.
credential = InteractiveBrowserCredential(
    disable_automatic_authentication=True)
client = SecretClient(VAULT_URL, credential)

try:
    secret_names = [s.name for s in client.list_properties_of_secrets()]
except AuthenticationRequiredError as ex:
    # Interactive authentication is necessary to authorize the client's request. The exception carries the
    # requested authentication scopes. If you pass these to 'authenticate', it will cache an access token
    # for those scopes.
    credential.authenticate(scopes=ex.scopes)

# the client operation should now succeed
secret_names = [s.name for s in client.list_properties_of_secrets()]
Пример #29
0
def test_interactive_credential(mock_open):
    mock_open.side_effect = _validate_auth_request_url
    oauth_state = "state"
    client_id = "client-id"
    expected_refresh_token = "refresh-token"
    expected_token = "access-token"
    expires_in = 3600
    authority = "authority"
    tenant_id = "tenant_id"
    endpoint = "https://{}/{}".format(authority, tenant_id)

    discovery_response = mock_response(
        json_payload={
            name: endpoint
            for name in ("authorization_endpoint", "token_endpoint",
                         "tenant_discovery_endpoint")
        })
    transport = validating_transport(
        requests=[Request(url_substring=endpoint)] * 3 + [
            Request(authority=authority,
                    url_substring=endpoint,
                    required_data={"refresh_token": expected_refresh_token})
        ],
        responses=[
            discovery_response,  # instance discovery
            discovery_response,  # tenant discovery
            mock_response(json_payload=build_aad_response(
                access_token=expected_token,
                expires_in=expires_in,
                refresh_token=expected_refresh_token,
                uid="uid",
                utid="utid",
                token_type="Bearer",
            )),
            mock_response(
                json_payload=build_aad_response(access_token=expected_token,
                                                expires_in=expires_in,
                                                token_type="Bearer")),
        ],
    )

    # mock local server fakes successful authentication by immediately returning a well-formed response
    auth_code_response = {"code": "authorization-code", "state": [oauth_state]}
    server_class = Mock(return_value=Mock(
        wait_for_redirect=lambda: auth_code_response))

    credential = InteractiveBrowserCredential(
        authority=authority,
        tenant_id=tenant_id,
        client_id=client_id,
        client_secret="secret",
        server_class=server_class,
        transport=transport,
        instance_discovery=False,
        validate_authority=False,
    )

    # The credential's auth code request includes a uuid which must be included in the redirect. Patching to
    # set the uuid requires less code here than a proper mock server.
    with patch("azure.identity._credentials.browser.uuid.uuid4",
               lambda: oauth_state):
        token = credential.get_token("scope")
    assert token.token == expected_token
    assert mock_open.call_count == 1

    # token should be cached, get_token shouldn't prompt again
    token = credential.get_token("scope")
    assert token.token == expected_token
    assert mock_open.call_count == 1

    # As of MSAL 1.0.0, applications build a new client every time they redeem a refresh token.
    # Here we patch the private method they use for the sake of test coverage.
    # TODO: this will probably break when this MSAL behavior changes
    app = credential._get_app()
    app._build_client = lambda *_: app.client  # pylint:disable=protected-access
    now = time.time()

    # expired access token -> credential should use refresh token instead of prompting again
    with patch("time.time", lambda: now + expires_in):
        token = credential.get_token("scope")
    assert token.token == expected_token
    assert mock_open.call_count == 1

    # ensure all expected requests were sent
    assert transport.send.call_count == 4
def test_no_scopes():
    """The credential should raise when get_token is called with no scopes"""

    with pytest.raises(ValueError):
        InteractiveBrowserCredential().get_token()