taverntesting/tavern

2FA Log In

MorganFujimaka opened this issue · 2 comments

What would be the best strategy to test API having a 2FA login (e.g. Okta via Authlib)?

Is it possible to log in using django.test.Client rather than API and have the logged-in user in the following stages?:

from django.test import Client

client.login(username, password)

I haven't used Django for a while but I think there's 2 options to do this: Either write a fixture that logs in using the django client and get the cookies:

import http.cookies
from django.test import Client


def django_cookies(client: Client) -> http.cookies.SimpleCookie:
    client.login("username", "password")

    return client.cookies
---
test_name: Use Django client to create cookies

marks:
  - usefixtures: django_login

stages:
  - name: Do a request with cookies
    request:
      url: "{host}/thing"
      method: GET
    cookies:
      - my_cookie_name: "{django_cookies.my_cookie_name}"

If that doesn't work, you'd probably have to write a plugin that
logged in via the Django authentication system and then used the client to do all future http requests

Hi @michaelboulton, thank you for the prompt reply.

I haven't tried writing a custom plugin, but passing a sessionid in cookies works like a charm. The issue is that I have many tests, and passing the cookies with every request looks tedious. I tried to use the pytest_tavern_beta_before_every_request hook, but it didn't work.

So, I decided to mock OAuth:

from unittest import mock

class MockOAuth():
    class MockOktaUserInfoResponse():
        def __init__(self, email):
            self.email = email


        def raise_for_status(*args, **kwargs):
            return None


        def json(self):
            if self.email:
                return { "email": self.email }
            else:
                return {}


    class MockOkta():
        def authorize_access_token(self, request):
            return request.POST.get("email")


        def get(self, userinfo_uri, token):
            return MockOAuth.MockOktaUserInfoResponse(email=token)


    def __init__(self):
        self.okta = MockOAuth.MockOkta()


    def register(*args, **kwargs):
        return True


@pytest.fixture(autouse=True)
def mock_okta():
    with mock.patch("authlib.integrations.django_client.OAuth", new=MockOAuth):
        yield