Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom auth backend compatibility for TenantClient #228

Merged
merged 1 commit into from
Apr 4, 2019

Conversation

ishtiaque06
Copy link
Contributor

Rationale: I'm creating a B2B multitenant app that logs in user using a custom auth backend which uses e-mail as one of the identifiers and authenticates users by parsing request.META['HTTP_HOST'] to get the relevant schema. However, by doing this, I wasn't able to use TenantClient's login() method since my custom auth backend needs a request object but django client's login method chain (login -> authenticate(**credentials)->... as shown here) doesn't pass on a request object to my custom auth backend.

Since I feel like B2B multitenant apps may often use custom auth backends like I did, I felt it necessary to propose this change.

**Rationale**: I'm creating a B2B multitenant app that logs in user using a custom auth backend which uses e-mail as one of the identifiers and authenticates users by parsing `request.META['HTTP_HOST']` to get the relevant schema. However, by doing this, I wasn't able to use `TenantClient`'s `login()` method since my custom auth backend needs a request object but django client's `login` method chain (`login -> authenticate(**credentials)->... ` [as shown here](https://github.com/django/django/blob/master/django/test/client.py#L594)) doesn't pass on a `request` object to my custom auth backend. 

Since I feel like B2B multitenant apps may often use custom auth backends like I did, I felt it necessary to propose this change.
@tomturner
Copy link
Member

@ishtiaque06 I can't see a problem this going in I will test it and merge in.

Thanks

Tom

@lorinkoz
Copy link
Contributor

@ishtiaque06 Question: why not use the provided request factory?

@ishtiaque06
Copy link
Contributor Author

@ishtiaque06 Question: why not use the provided request factory?

@lorinkoz I'm not sure I understand how I'd go about doing that. Could you point me to the right direction?

@ishtiaque06
Copy link
Contributor Author

@ishtiaque06 Question: why not use the provided request factory?

Just read the docs. I will try this out to see if it works and keep you updated. Thank you! This is a much neater way of doing things (not up in the "Advanced Testing" alley yet).

@lorinkoz
Copy link
Contributor

There is a RequestFactory for testing purposes at https://github.com/tomturner/django-tenants/blob/master/django_tenants/test/client.py

I think this is the recommended way to create requests for testing.

@ishtiaque06
Copy link
Contributor Author

ishtiaque06 commented Jan 22, 2019

There is a RequestFactory for testing purposes at https://github.com/tomturner/django-tenants/blob/master/django_tenants/test/client.py

I think this is the recommended way to create requests for testing.

So I tried out TenantRequestFactory. It's pretty nifty. However, when I'm using this, I can't conveniently test various aspects of the response that I would be able to access with the TenantClient like assertTemplateUsed or response.context['variable_goes_here'] to see if the right queryset is being sent by the views I'm testing, which for me is the point of integration testing in Django.

EDIT: I know I probably would manually be able to synthesize all those aspects I wanted to test but it seems a little redundant if there's a global feature that enables me to do it for all tests I run using the test client.

@ishtiaque06
Copy link
Contributor Author

@ishtiaque06 I can't see a problem this going in I will test it and merge in.

Thanks

Tom

This is the custom authentication backend I'm trying to use if you want to work with it:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django_tenants.utils import schema_context


# Custom backend to enable logging in with e-mail.
# https://stackoverflow.com/questions/37332190/django-login-with-email
class EmailAuthBackend(ModelBackend):

    def authenticate(self, request, username=None, password=None, *args):
        if request == None:
            print ("args:", *args)
        # schema = request.build_absolute_uri().split('.')[0].split('/')[-1]
        schema = request.META['HTTP_HOST'].split('.')[0]
        if (schema == 'dibs-test'):
            return None
        with schema_context(schema):
            UserModel = get_user_model()
            try:
                user = UserModel.objects.get(email=username)
            except UserModel.DoesNotExist:
                return None
            else:
                if user.check_password(password):
                    return user
            return None

@tomturner tomturner merged commit e776b8a into django-tenants:master Apr 4, 2019
tomturner added a commit that referenced this pull request Apr 4, 2019
@tomturner
Copy link
Member

@ishtiaque06 Thanks I have committed this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants