django-allauth: Only allow users from a specific google apps domain
Answering my own question-
What you want to do is stall the login after a user has been authenticated by a social account provider and before they can proceed to their profile page. You can do this with the
pre_social_login method of the DefaultSocialAccountAdapter class in allauth/socialaccount/adaptor.py
Invoked just after a user successfully authenticates via asocial provider, but before the login is actually processed(and before the pre_social_login signal is emitted).You can use this hook to intervene, e.g. abort the login byraising an ImmediateHttpResponseWhy both an adapter hook and the signal? Intervening ine.g. the flow from within a signal handler is bad -- multiplehandlers may be active and are executed in undetermined order.
Do something like
from allauth.socialaccount.adaptor import DefaultSocialAccountAdapterclass MySocialAccount(DefaultSocialAccountAdapter): def pre_social_login(self, request, sociallogin): u = sociallogin.account.user if not u.email.split('@')[1] == "example.com" raise ImmediateHttpResponse(render_to_response('error.html'))
This is not an exact implementation but something like this works.
Here's an alternate solution:
from allauth.account.adapter import DefaultAccountAdapterfrom allauth.socialaccount.adapter import DefaultSocialAccountAdapterclass CustomAccountAdapter(DefaultAccountAdapter): def is_open_for_signup(self, request): return False # No email/password signups allowedclass CustomSocialAccountAdapter(DefaultSocialAccountAdapter): def is_open_for_signup(self, request, sociallogin): u = sociallogin.user # Optionally, set as staff now as well. # This is useful if you are using this for the Django Admin login. # Be careful with the staff setting, as some providers don't verify # email address, so that could be considered a security flaw. #u.is_staff = u.email.split('@')[1] == "customdomain.com" return u.email.split('@')[1] == "customdomain.com"
This code can live anywhere, but assuming it's in mysite/adapters.py
, you'll also need the following in your settings.py
:
ACCOUNT_ADAPTER = 'mysite.adapters.CustomAccountAdapter'SOCIALACCOUNT_ADAPTER = 'mysite.adapters.CustomSocialAccountAdapter'
You could do something in the line of overriding allauth's allauth.socialaccount.forms.SignupForm and checking the domain during the signup process.Discalmer: this is all written without testing, but something in the line of that should work.
# settings.py# not necesarry, but it would be a smart way to go instead of hardcoding itALLOWED_DOMAIN = 'example.com'
.
# forms.pyfrom django.conf import settingsfrom allauth.socialaccount.forms import SignupFormclass MySignupForm(SignupForm): def clean_email(self): data = self.cleaned_data['email'] if data.split('@')[1].lower() == settings.ALLOWED_DOMAIN: raise forms.ValidationError(_(u'domena!')) return data
in your urls override allauth defaults (put this before the include of django-allauth)
# urls.pyfrom allauth.socialaccount.views import SignupViewfrom .forms import MySignupFormurlpatterns = patterns('', # ... url(r"^social/signup/$", SignupView.as_view(form_class=MySignupForm), name="account_signup"), # ...)
I'm not sure for the "^social/signup/$", recheck that.