async def test_client_success_call_oauth(fs, monkeypatch):
    oauth_client = Client({
        "orgUrl": ORG_URL,
        "authorizationMode": "PrivateKey",
        "clientId": CLIENT_ID,
        "scopes": SCOPES,
        "privateKey": PRIVATE_KEY
    })

    request_executor = oauth_client.get_request_executor()

    monkeypatch.setattr(OAuth, 'get_access_token', mocks.mock_access_token)
    req, err = await request_executor.create_request("GET", GET_USERS_CALL, {},
                                                     {})

    req, res_details, resp_body, error = await oauth_client\
        .get_request_executor().fire_request(req)

    assert error is None
    assert "User-Agent" in req["headers"]
    assert "Authorization" in req["headers"]
    assert req["headers"]["Authorization"].startswith("Bearer")
    assert res_details.status == 200
    assert "application/json" in res_details.headers["Content-Type"]
    assert resp_body is not None
Beispiel #2
0
async def test_response_pagination_with_next(monkeypatch):
    ssws_client = Client({
        "orgUrl": ORG_URL,
        "token": API_TOKEN
    })

    req, error = await ssws_client.get_request_executor()\
        .create_request("GET",
                        GET_USERS_CALL + API_LIMIT,
                        {},
                        {})

    monkeypatch.setattr(RequestExecutor, 'fire_request',
                        mocks.mock_GET_HTTP_Client_response_valid_with_next)

    result, error = await ssws_client.get_request_executor().execute(req)

    assert result.get_body() is not None
    assert result.has_next()
    monkeypatch.setattr(RequestExecutor, 'fire_request',
                        mocks.mock_GET_HTTP_Client_response_valid)
    assert await result.next() is not None
    assert not result.has_next()
    with pytest.raises(StopAsyncIteration):
        await result.next()
def test_known_sign_on_mode():
    response = copy.deepcopy(SAML_APP_RESP_DICT)

    config = {
        "orgUrl": "https://test_org.okta.com",
        "token": "test_token",
        "requestExecutor": MockRequestExecutor,
    }
    client = Client(config)

    # check list applications
    client._request_executor.set_response([response])
    event_loop = asyncio.get_event_loop()
    result, resp, err = event_loop.run_until_complete(
        client.list_applications())
    assert type(result[0]) == SamlApplication
    assert result[0].as_dict() == EXPECTED_SAML_APP_AS_DICT

    # check get application
    client._request_executor.set_response(response)
    event_loop = asyncio.get_event_loop()
    result, resp, err = event_loop.run_until_complete(
        client.get_application("test_id"))
    assert type(result) == SamlApplication
    assert result.as_dict() == EXPECTED_SAML_APP_AS_DICT
async def test_client_error_call_oauth(fs, monkeypatch):
    oauth_client = Client({
        "orgUrl": ORG_URL,
        "authorizationMode": "PrivateKey",
        "clientId": CLIENT_ID,
        "scopes": SCOPES,
        "privateKey": PRIVATE_KEY + "Wrong one"
    })

    monkeypatch.setattr(OAuth, 'get_access_token', mocks.mock_access_token)

    req, err = await oauth_client.get_request_executor()\
        .create_request("GET",
                        GET_USERS_CALL,
                        {},
                        {})

    req, res_details, resp_body, error = await oauth_client\
        .get_request_executor().fire_request(req)

    parsed, error = HTTPClient.check_response_for_error(
        req["url"], res_details, resp_body)

    assert parsed is None
    assert res_details.status == 404
    assert isinstance(error, HTTPError)
    assert error.message.startswith("HTTP 404")
async def test_no_x_reset_header(monkeypatch):
    client = Client(user_config=CLIENT_CONFIG)

    monkeypatch.setattr(HTTPClient, 'send_request',
                        mocks.mock_GET_HTTP_Client_response_429_no_x_reset)
    monkeypatch.setattr(time, 'sleep', mocks.mock_pause_function)

    users, resp, error = await client.list_users()

    assert error is not None
    assert isinstance(error, Exception)
    assert error.args[0] == ERROR_MESSAGE_429_MISSING_DATE_X_RESET
    assert users is None
    assert resp is None
async def test_backoff_calculation():
    client = Client(user_config=CLIENT_CONFIG)

    response_429 = (await mocks.mock_GET_HTTP_Client_response_429())[1]
    # ^ has a 1 second difference in retry and datetime
    # backoff should be 2 by Okta standards

    retry_limit_reset = float(response_429.headers["X-Rate-Limit-Reset"])
    date_time = convert_date_time_to_seconds(response_429.headers["Date"])

    backoff_time = client.get_request_executor().calculate_backoff(
        retry_limit_reset, date_time)

    assert (backoff_time == 2)
async def test_multiple_x_reset_headers(monkeypatch, mocker):
    client = Client(user_config=CLIENT_CONFIG)

    backoff_spy = mocker.spy(RequestExecutor, 'calculate_backoff')

    monkeypatch.setattr(HTTPClient, 'send_request',
                        mocks.mock_GET_HTTP_Client_response_429_multi_x_reset)
    # the X Rate Limit Resets used are 1 sec and 2 sec after the Date header,
    # -> the min. one should be used (1 sec. after) and the backoff calculated
    #    should be equal to 2 (by Okta standards)
    monkeypatch.setattr(time, 'sleep', mocks.mock_pause_function)

    users, resp, error = await client.list_users()

    assert error is not None
    assert users is None
    assert backoff_spy.spy_return == 2
Beispiel #8
0
async def test_response_headers(monkeypatch):
    ssws_client = Client({
        "orgUrl": ORG_URL,
        "token": API_TOKEN
    })

    req, error = await ssws_client.get_request_executor()\
        .create_request("GET",
                        GET_USERS_CALL + API_LIMIT,
                        {},
                        {})

    monkeypatch.setattr(RequestExecutor, 'fire_request',
                        mocks.mock_GET_HTTP_Client_response_valid)

    result, error = await ssws_client.get_request_executor().execute(req)
    assert result.get_body() is not None
    assert result.get_headers() == mocks.MockHTTPResponseDetails().headers
def test_unknown_sign_on_mode():
    response = copy.deepcopy(SAML_APP_RESP_DICT)
    response["signOnMode"] = "UNKNOWN_SIGN_ON_MODE"
    expected = copy.deepcopy(EXPECTED_SAML_APP_AS_DICT)
    expected["signOnMode"] = ApplicationSignOnMode("UNKNOWN_SIGN_ON_MODE")
    expected["settings"] = {
        "app": {},
        "notifications": {
            "vpn": {
                "network": {
                    "connection": "DISABLED",
                    "exclude": [],
                    "include": []
                }
            }
        },
    }

    config = {
        "orgUrl": "https://test_org.okta.com",
        "token": "test_token",
        "requestExecutor": MockRequestExecutor,
    }
    client = Client(config)

    # check list applications
    client._request_executor.set_response([response])
    event_loop = asyncio.get_event_loop()
    result, resp, err = event_loop.run_until_complete(
        client.list_applications())
    # verify if result fallbacks to generic Application
    assert type(result[0]) != SamlApplication
    assert type(result[0]) == Application
    assert result[0].as_dict() == expected

    # check get application
    client._request_executor.set_response(response)
    event_loop = asyncio.get_event_loop()
    result, resp, err = event_loop.run_until_complete(
        client.get_application("test_id"))
    # verify if result fallbacks to generic Application
    assert type(result) != SamlApplication
    assert type(result) == Application
    assert result.as_dict() == expected
async def test_req_timeout(monkeypatch):
    this_config = CLIENT_CONFIG.copy()
    this_config.update({"requestTimeout": 1})
    client = Client(user_config=this_config)

    request = await mocks.mock_GET_HTTP_request()

    monkeypatch.setattr(HTTPClient, 'send_request',
                        mocks.mock_GET_HTTP_Client_response_429)

    now = dt.datetime.now(dt.timezone.utc)
    now = now.replace(microsecond=0)
    two_sec_before = (now - dt.timedelta(seconds=2)).timestamp()

    a, b, c, error = await client.get_request_executor().fire_request_helper(
        request, 0, two_sec_before)

    assert isinstance(error, Exception)
    assert "Request Timeout exceeded." == error.args[0]
async def test_max_retries_no_timeout(monkeypatch, mocker):
    client = Client(user_config=CLIENT_CONFIG)
    query_params = {"limit": "1"}

    monkeypatch.setattr(HTTPClient, 'send_request',
                        mocks.mock_GET_HTTP_Client_response_429)

    monkeypatch.setattr(time, 'sleep', mocks.mock_pause_function)

    http_spy = mocker.spy(HTTPClient, 'send_request')

    users, resp, error = await client.list_users(query_params)

    http_spy.assert_called()
    assert http_spy.call_count ==\
        client.get_request_executor()._max_retries + 1
    assert client.get_request_executor()._request_timeout == 0
    assert isinstance(error, HTTPError)
    assert error is not None
    assert error.status == HTTPStatus.TOO_MANY_REQUESTS
    assert resp.get_status() == HTTPStatus.TOO_MANY_REQUESTS
async def test_client_error_call_SSWS(fs):
    ssws_client = Client({
        "orgUrl": ORG_URL,
        "token": API_TOKEN + "wrong token"
    })

    req, error = await ssws_client.get_request_executor()\
        .create_request("GET",
                        GET_USERS_CALL,
                        {},
                        {})

    req, res_details, resp_body, error = await ssws_client\
        .get_request_executor().fire_request(req)

    parsed, error = HTTPClient.check_response_for_error(
        req["url"], res_details, resp_body)

    assert parsed is None
    assert res_details.status == 404
    assert isinstance(error, HTTPError)
    assert error.message.startswith("HTTP 404")
Beispiel #13
0
async def test_response_pagination_with_next_not_starting_with_api(monkeypatch):
    ssws_client = Client(CLIENT_CONFIG)

    req, error = await ssws_client.get_request_executor() \
        .create_request("GET",
                        GET_OAUTH_CLIENTS_CALL + API_LIMIT,
                        {},
                        {})

    monkeypatch.setattr(RequestExecutor, 'fire_request',
                        mocks.mock_GET_HTTP_Client_response_valid_with_next)

    result, error = await ssws_client.get_request_executor().execute(req)

    assert result.get_body() is not None
    assert result.has_next()
    assert result._next.startswith(GET_OAUTH_CLIENTS_CALL)
    monkeypatch.setattr(RequestExecutor, 'fire_request',
                        mocks.mock_GET_HTTP_Client_response_valid)
    assert await result.next() is not None
    assert not result.has_next()
    with pytest.raises(StopAsyncIteration):
        await result.next()
Beispiel #14
0
    async def test_list_supported_security_questions(self):
        # Instantiate Mock Client
        client = MockOktaClient(fs)
        client = Client()

        # Create User
        user_profile = models.UserProfile()
        user_profile.first_name = "John"
        user_profile.last_name = "Doe-List-Security-Question"
        user_profile.email = "*****@*****.**"
        user_profile.login = "******"

        create_user_req = models.CreateUserRequest({
            "credentials":
            models.UserCredentials({
                "password":
                models.PasswordCredential({"value": "Password150kta"})
            }),
            "profile":
            user_profile
        })

        created_user, _, err = await client.create_user(create_user_req)
        assert err is None
        assert isinstance(created_user, models.User)

        # Create and add factor
        sec_q_factor = models.SecurityQuestionUserFactor({
            "factorType":
            models.FactorType.QUESTION,
            "provider":
            models.FactorProvider.OKTA,
            "profile":
            models.SecurityQuestionUserFactorProfile({
                "question": "disliked_food",
                "answer": "lasagna"
            })
        })

        enrolled_factor, _, err = await \
            client.enroll_factor(created_user.id, sec_q_factor)
        assert err is None
        assert isinstance(enrolled_factor, models.SecurityQuestionUserFactor)

        # List factor to validate
        users_factors, _, err = await client.list_factors(created_user.id)
        assert err is None
        assert len(users_factors) > 0 and len(users_factors) == 1
        assert isinstance(users_factors[0], models.SecurityQuestionUserFactor)
        assert users_factors[0].factor_type == models.FactorType.QUESTION
        assert users_factors[0].id == sec_q_factor.id
        assert users_factors[0].profile.question ==\
            sec_q_factor.profile.question
        assert users_factors[0].profile.answer == sec_q_factor.profile.answer
        assert users_factors[0].profile.question_text

        # List Security q's
        retrieved_questions, _, err = await \
            client.list_supported_security_questions(created_user.id)
        assert err is None
        assert next(
            (question for question in retrieved_questions
             if question.profile.question == enrolled_factor.profile.question))

        # Deactivate + delete user
        _, err = await client.deactivate_user(created_user.id)
        assert err is None
        _, err = await client.deactivate_or_delete_user(created_user.id)
        assert err is None
Beispiel #15
0
    async def test_reset_factors(self):
        # Instantiate Mock Client
        client = MockOktaClient(fs)
        client = Client()

        # Create User
        user_profile = models.UserProfile()
        user_profile.first_name = "John"
        user_profile.last_name = "Doe-Reset-Factor"
        user_profile.email = "*****@*****.**"
        user_profile.login = "******"

        create_user_req = models.CreateUserRequest({
            "credentials":
            models.UserCredentials({
                "password":
                models.PasswordCredential({"value": "Password150kta"})
            }),
            "profile":
            user_profile
        })

        created_user, _, err = await client.create_user(create_user_req)
        assert err is None
        assert isinstance(created_user, models.User)

        # Create and add factor
        sms_factor = models.SmsUserFactor({
            "profile":
            models.SmsUserFactorProfile({"phoneNumber": "+12345678901"})
        })

        enrolled_factor, _, err = await \
            client.enroll_factor(created_user.id, sms_factor)
        assert err is None
        assert isinstance(enrolled_factor, models.SmsUserFactor)

        # Get factor to validate
        retrieved_user_factor, _, err = await client.get_factor(
            created_user.id, enrolled_factor.id)
        assert err is None
        assert isinstance(retrieved_user_factor, models.SmsUserFactor)
        assert retrieved_user_factor.id == enrolled_factor.id
        assert retrieved_user_factor.factor_type == models.FactorType.SMS
        assert retrieved_user_factor.profile.phone_number ==\
            sms_factor.profile.phone_number

        # Reset factor
        _, err = await client.reset_factors(created_user.id)
        assert err is None

        # List factors to validate
        users_factors, _, err = await client.list_factors(created_user.id)
        assert err is None
        assert len(users_factors) == 0

        # Deactivate + delete user
        _, err = await client.deactivate_user(created_user.id)
        assert err is None
        _, err = await client.deactivate_or_delete_user(created_user.id)
        assert err is None