示例#1
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
示例#2
0
def test_adfs():
    """the credential should be able to construct an AuthenticationRecord from an ADFS response returned by MSAL"""

    authority = "localhost"
    subject = "subject"
    tenant = "adfs"
    username = "******"
    msal_response = build_aad_response(access_token="***", refresh_token="**")
    msal_response["id_token_claims"] = id_token_claims(
        aud="client-id",
        iss="https://{}/{}".format(authority, tenant),
        sub=subject,
        tenant_id=tenant,
        object_id="object-id",
        upn=username,
    )

    class TestCredential(InteractiveCredential):
        def __init__(self, **kwargs):
            super(TestCredential, self).__init__(client_id="...", **kwargs)

        def _request_token(self, *_, **__):
            return msal_response

    record = TestCredential().authenticate()
    assert record.authority == authority
    assert record.home_account_id == subject
    assert record.tenant_id == tenant
    assert record.username == username
def test_claims_challenge():
    """get_token should pass any claims challenge to MSAL token acquisition APIs"""

    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"),
    )
    expected_claims = '{"access_token": {"essential": "true"}'

    transport = Mock(send=Mock(side_effect=Exception(
        "this test mocks MSAL, so no request should be sent")))
    credential = DeviceCodeCredential(transport=transport)
    with patch.object(DeviceCodeCredential, "_get_app") as get_mock_app:
        msal_app = get_mock_app()
        msal_app.initiate_device_flow.return_value = {"message": "it worked"}
        msal_app.acquire_token_by_device_flow.return_value = msal_acquire_token_result
        credential.get_token("scope", claims=expected_claims)

        assert msal_app.acquire_token_by_device_flow.call_count == 1
        args, kwargs = msal_app.acquire_token_by_device_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
def test_claims_challenge():
    """get_token should and authenticate pass any claims challenge to MSAL token acquisition APIs"""

    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"),
    )
    expected_claims = '{"access_token": {"essential": "true"}'

    transport = Mock(send=Mock(side_effect=Exception("this test mocks MSAL, so no request should be sent")))
    credential = UsernamePasswordCredential("client-id", "username", "password", transport=transport)
    with patch.object(UsernamePasswordCredential, "_get_app") as get_mock_app:
        msal_app = get_mock_app()
        msal_app.acquire_token_by_username_password.return_value = msal_acquire_token_result

        credential.authenticate(scopes=["scope"], claims=expected_claims)
        assert msal_app.acquire_token_by_username_password.call_count == 1
        args, kwargs = msal_app.acquire_token_by_username_password.call_args
        assert kwargs["claims_challenge"] == expected_claims

        credential.get_token("scope", claims=expected_claims)

        assert msal_app.acquire_token_by_username_password.call_count == 2
        args, kwargs = msal_app.acquire_token_by_username_password.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
 async def send(request, **_):
     parsed = urlparse(request.url)
     tenant_id = parsed.path.split("/")[1]
     assert tenant_id == default_tenant
     return mock_response(json_payload=build_aad_response(
         access_token=expected_token,
         id_token_claims=id_token_claims(aud="...", iss="...", sub="..."),
     ))
 async def send(request, **_):
     parsed = urlparse(request.url)
     tenant_id = parsed.path.split("/")[1]
     return mock_response(json_payload=build_aad_response(
         access_token=second_token if tenant_id ==
         second_tenant else first_token,
         id_token_claims=id_token_claims(aud="...", iss="...", sub="..."),
     ))
示例#7
0
 def send(request, **_):
     parsed = urlparse(request.url)
     tenant_id = parsed.path.split("/")[1]
     assert tenant_id in (default_tenant, second_tenant), 'unexpected tenant "{}"'.format(tenant_id)
     return mock_response(
         json_payload=build_aad_response(
             access_token=second_token if tenant_id == second_tenant else first_token,
             id_token_claims=id_token_claims(aud="...", iss="...", sub="..."),
         )
     )
示例#8
0
 def request_token(*_, **__):
     return build_aad_response(
         access_token=expected_token,
         id_token_claims=id_token_claims(
             aud="...",
             iss="http://localhost/tenant",
             sub="subject",
             preferred_username="******",
             tenant_id="...",
             object_id="...",
         ),
     )
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
示例#10
0
    def send(request, **_):
        parsed = urlparse(request.url)
        tenant_id = parsed.path.split("/")[1]
        if "/oauth2/v2.0/token" not in request.url:
            return get_discovery_response("https://{}/{}".format(parsed.netloc, tenant_id))

        assert tenant_id in (default_tenant, second_tenant), 'unexpected tenant "{}"'.format(tenant_id)
        return mock_response(
            json_payload=build_aad_response(
                access_token=second_token if tenant_id == second_tenant else first_token,
                id_token_claims=id_token_claims(aud="...", iss="...", sub="..."),
            )
        )
示例#11
0
 def request_token(*args, **kwargs):
     tenant_id = kwargs.get("tenant_id")
     return build_aad_response(
         access_token=second_token
         if tenant_id == second_tenant else first_token,
         id_token_claims=id_token_claims(
             aud="...",
             iss="http://localhost/tenant",
             sub="subject",
             preferred_username="******",
             tenant_id="...",
             object_id="...",
         ),
     )
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
示例#13
0
from six.moves.urllib_parse import urlparse

try:
    from unittest.mock import Mock, patch
except ImportError:  # python < 3.3
    from mock import Mock, patch  # type: ignore

from helpers import build_aad_response, get_discovery_response, id_token_claims

# fake object for tests which need to exercise request_token but don't care about its return value
REQUEST_TOKEN_RESULT = build_aad_response(
    access_token="***",
    id_token_claims=id_token_claims(
        aud="...",
        iss="http://localhost/tenant",
        sub="subject",
        preferred_username="******",
        tenant_id="...",
        object_id="...",
    ),
)


class MockCredential(InteractiveCredential):
    """Test class to drive InteractiveCredential.

    Default instances have an empty in-memory cache, and raise rather than send an HTTP request.
    """
    def __init__(self,
                 client_id="...",
                 request_token=None,
                 transport=None,