Require minimum password complexity in django allauth - django

I am trying to implement a minimum set of criteria for passwords. However, even with the below, users are able to sign up with a single character password. How can I require a certain minimum password complexity when using django-allauth with a custom adapter.
# adapter.py
from typing import Any
from allauth.account.adapter import DefaultAccountAdapter
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.exceptions import ImmediateHttpResponse
from django.conf import settings
from django.forms import ValidationError
from django.http import HttpRequest
class AccountAdapter(DefaultAccountAdapter):
def is_open_for_signup(self, request: HttpRequest):
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
def clean_password(self, password, user=None):
special_characters = "[~\!##\$%\^&\*\(\)_\+{}\":;'\[\]]"
min_length = 1
if len(password) < 8:
raise ValidationError('Password length must be greater than 8 characters.')
if not any(char.isdigit() for char in password):
raise ValidationError('Password must contain at least %(min_length)d digits.') % {'min_length': min_length}
if not any(char.isalpha() for char in password):
raise ValidationError('Password must contain at least %(min_length)d letters.') % {'min_length': min_length}
if not any(char in special_characters for char in password):
raise ValidationError('Password must contain at least %(min_length)d special characters.') % {'min_length': min_length}
return password
class SocialAccountAdapter(DefaultSocialAccountAdapter):
def is_open_for_signup(self, request: HttpRequest, sociallogin: Any):
return getattr(settings, "ACCOUNT_ALLOW_REGISTRATION", True)
# settings.py
# https://django-allauth.readthedocs.io/en/latest/configuration.html
ACCOUNT_ADAPTER = "project.adapters.user.AccountAdapter"
# https://django-allauth.readthedocs.io/en/latest/forms.html
ACCOUNT_FORMS = {"signup": "project.forms.user.UserSignupForm"}
# https://django-allauth.readthedocs.io/en/latest/configuration.html
SOCIALACCOUNT_ADAPTER = "project.adapters.user.SocialAccountAdapter"

I was able to address the issue not using an adapter but putting this in the forms.py
def clean_password(self):
special_characters = "[~\!##\$%\^&\*\(\)_\+{}\":;'\[\]]"
if len(self.data['password']) < 8:
raise ValidationError('Password length must be greater than 8 characters.')
if not any(char.isdigit() for char in self.data['password']):
raise ValidationError('Password must contain at least 1 digit.')
if not any(char.isalpha() for char in self.data['password']):
raise ValidationError('Password must contain at least 1 letter.')
if not any(char in special_characters for char in self.data['password']):
raise ValidationError('Password must contain at least 1 special characters.')
return self.data['password']

Related

During testing, when tested with correct user input, I get "Invalid credentials"

I am using just phone number alone as the only field for login.
Authentication does not seem to work well even when supplied with correct user input.
ERROR WHEN I CONFIGURE THE AUTH BACKENDS:
File "C:\Users\UBITEK\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\conf\__init__.py", line 161, in __init__
raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.
#csrf_exempt
#api_view(["POST"])
#permission_classes((AllowAny,))
def logins(request):
phone_number = request.data.get("phone_number")
if phone_number is None:
return Response({'error': 'Please provide your phone number'},
status=HTTP_400_BAD_REQUEST)
user = authenticate(phone_number=phone_number)
if not user:
return Response({'error': 'Invalid Credentials'},
status=HTTP_404_NOT_FOUND)
token, _ = Token.objects.get_or_create(user=user)
return Response({'token': token.key},
status=HTTP_200_OK)
backends.py
from django.contrib.auth.backends import ModelBackend
from .models import User
class LoginBackend(ModelBackend):
def authenticate(self, request, **kwargs):
phone_number= kwargs['phone_number']
user = User.objects.get(phone_number=phone_number)
if user:
return user
else:
return None
settings.py
from .backends import LoginBackend
from django.contrib.auth.backends import ModelBackend
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend',
'findr.backends.LoginBackend']
Regarding the comments on your question, I suggest you to write your own django authentification backend:
https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#writing-an-authentication-backend
You have to tell Django how someone should be authenticated:
with username and password?
with phone_number and password?
This has to be explicit (and do not forget to add this new backend to your settings.py file!).

Django Unit Testing (with DRF): How to test a Passwordresetview?

I'm currently trying to write my unittest for a successfull password reset.
TLDR: I can't figure out how to handle the injection of the form data in the post request in the set-password view.
For context, let me give you my code first, since a line of code speaks more than 1000 words.
accounts/api/views.py:
class PasswordResetView(generics.GenericAPIView):
"""(POST) Expects email. Sends a password reset mail to email."""
permission_classes = (permissions.AllowAny,)
serializer_class = PasswordResetSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid(raise_exception=True):
user = User.objects.get(email=serializer.data['email'])
if user.is_active and user.has_usable_password():
send_password_reset_email(user, request)
return Response(
{"detail": "A password reset email has been send."},
status=status.HTTP_204_NO_CONTENT
)
else:
return Response(
{"detail": "This users password can't be reset."},
status=status.HTTP_406_NOT_ACCEPTABLE
)
accounts/api/urls.py:
url(r'^password_reset/$', views.PasswordResetView.as_view(),
name="password_reset"),
accounts/api/serializers.py:
class PasswordResetSerializer(serializers.Serializer):
email = serializers.EmailField()
def validate_email(self, value):
if User.objects.filter(email__iexact=value).exists():
return value
else:
raise serializers.ValidationError("Email not found.")
accounts/utils.py:
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.contrib.sites.shortcuts import get_current_site
from django.utils import six
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from templated_email import send_templated_mail
password_reset_token = PasswordResetTokenGenerator()
def build_email_context(user_obj, request):
current_site = get_current_site(request)
context = {
"name": "",
"domain": current_site.domain,
"uid": urlsafe_base64_encode(force_bytes(user_obj.pk)),
'token': password_reset_token.make_token(user_obj)
}
if user_obj.name != "":
context["name"]: " " + user_obj.name
return context
def send_password_reset_email(user_obj, request):
context = build_email_context(user_obj, request)
send_templated_mail(
template_name="password_reset",
from_email="noreply#ordersome.com",
recipient_list=[user_obj.email],
context=context
)
The views that are linked to the route in the email are the standard CBV PasswordResetConfirmView and PasswordResetDoneView from django.contrib.auth.
And here is the test I wrote for this password reset sequence:
api/tests/test_views.py:
from django.contrib.auth import get_user, get_user_model
from django.core import mail
from rest_framework import status
from rest_framework.authtoken.models import Token
from rest_framework.reverse import reverse as api_reverse
from rest_framework.test import APITestCase
User = get_user_model()
class UserAPIViewsTestCase(APITestCase):
def setUp(self):
User.objects.create_user(
email="testuser#test.com", password="test1234")
self.login_url = api_reverse("api:auth:login")
self.register_url = api_reverse("api:auth:register")
self.password_reset_url = api_reverse("api:auth:password_reset")
self.password_change_url = api_reverse("api:auth:password_change")
self.user_delete_url = api_reverse("api:auth:user_delete")
def test_api_auth_password_reset_success(self):
"""Test if a password reset successfully resets password."""
pre_user = User.objects.get(email="testuser#test.com")
self.assertEqual(pre_user.check_password("test1234"), True)
email_data = {
"email": "testuser#test.com",
}
email_response = self.client.post(
self.password_reset_url, email_data, format="json")
self.assertEqual(email_response.status_code,
status.HTTP_204_NO_CONTENT)
password_reset_data = {
"new_password1": "newtest1234",
"new_password2": "newtest1234"
}
password_reset_response = self.client.get(
mail.outbox[0].body[-94:-37], format="json", follow=True)
path = password_reset_response.request["PATH_INFO"]
done_url = "http://testserver" + path
password_reset_done_response = self.client.post(
done_url, password_reset_data, format="json")
post_user = User.objects.get(email="testuser#test.com")
self.assertEqual(post_user.check_password("newtest1234"), True)
The last self.assertEqual fails. But when I test the view manually, it works, so the code should be correct. How should I modify the test?
When I log out done_url it gives me http://testserver/auth/reset/MQ/set-password/, which should be the correct path.
And when I log out password_reset_done_response it says, that it is a TemplateResponse and the status_code is 200 (which should mean successful, but it's not). Also this response still seems to have the path /auth/reset/MQ/set-password/ which should not be the case anymore.
password_reset_data is not complete - there's no info to which user the new password should be applied.
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
...
password_reset_data = {
'uid': urlsafe_base64_encode(force_bytes(pre_user.pk)),
'token': default_token_generator.make_token(pre_user),
'new_password1': 'newtest1234',
'new_password2': 'newtest1234',
}
Other suggestions
setUp(self) should call super().setUp()
Use self.assertTrue instead of self.assertEqual
post_user is not needed, use pre_user.refresh_from_db() before last assert

How do I connect admin page in django with custom auth backend?

I used a custom auth backend in my django project to connect users, my problem is that i'm not able to connect using the admin interface anymore.
this is my custom auth files :
auth_backends.py:
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_model
class StudentModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = self.user_class_s.objects.get(username=username)
if user.check_password(password):
return user
except self.user_class_s.DoesNotExist:
return None
def get_user(self, user_id):
try:
return self.user_class_s.objects.get(pk=user_id)
except self.user_class_s.DoesNotExist:
return None
#property
def user_class_s(self):
if not hasattr(self, '_user_class'):
self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.', 2))
if not self._user_class:
raise ImproperlyConfigured('Could not get student model')
return self._user_class
class ProfessorModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = self.user_class_p.objects.get(username=username)
if user.check_password(password):
return user
except self.user_class_p.DoesNotExist:
return None
def get_user(self, user_id):
try:
return self.user_class_p.objects.get(pk=user_id)
except self.user_class_p.DoesNotExist:
return None
#property
def user_class_p(self):
if not hasattr(self, '_user_class'):
self._user_class = get_model(*settings.CUSTOM_USER_MODEL_P.split('.', 2))
if not self._user_class:
raise ImproperlyConfigured('Could not get student model')
return self._user_class
settings.py:
AUTHENTICATION_BACKENDS = (
'authentification.auth_backends.StudentModelBackend',
'authentification.auth_backends.ProfessorModelBackend',
)
CUSTOM_USER_MODEL = 'forum.Student'
CUSTOM_USER_MODEL_P = 'forum.Professor'
I tried this solution :
from django.contrib.auth.decorators import login_required
admin.autodiscover()
admin.site.login = login_required(admin.site.login)
but it redirect me to the user auth interface instead of admin interface.
Could someone help me please ?
I Found the solution,
i just have to tell django to try connecting using the original backend if the user isnt a student or professor.
just add 'django.contrib.auth.backends.ModelBackend' in settings.py
settings.py :
AUTHENTICATION_BACKENDS = (
'authentification.auth_backends.StudentModelBackend',
'authentification.auth_backends.ProfessorModelBackend',
'django.contrib.auth.backends.ModelBackend',
)
The default login_required decorator will default to the settings.py LOGIN_REDIRECT_URL. However, you can also explicitly tell it which login view to use by passing the login_url keyword argument.
https://github.com/django/django/blob/stable/1.8.x/django/contrib/auth/decorators.py#L39
This may be used with the generic login_required view and my samples below show more precise conditionals by using the user_passes_test decorator.
For instance:
from django.contrib.auth.decorators import user_passes_test
def superuser_required(*args, **kwargs):
return user_passes_test(lambda u: u.is_superuser, login_url='admin:login')(*args, **kwargs)
def custom_login_required(*args, **kwargs):
return user_passes_test(lambda u: getattr(u, 'is_custom_user', False), login_url='custom-url-name-from-urls-py')(*args, **kwargs)
Then you should be able to use this new decorate as you have above with the generic login_required:
admin.site.login = custom_login_required(admin.site.login)

Tastypie, non-orm endpoints

I'm trying to figure out if it makes sense to create non-orm endpoints for my api. I've seen the "Using Tastypie With Non-ORM Data Sources" section of the Docs, but I'm thinking more about processing forms and such. For example: Passing data to an end point that would process and send email. Im not gonna save anything to the db, I just want to validate the form and send it. Am I missing something in the docs or am I just barking up the wrong tree?
I think you can just define a function in your views.py and handle the request without it really using tastypie:
Here's an example for registering a new user to to a Django webapp; you can probably repurpose it to send an e-mail instead by processing the form data from the request.
# In views.py:
...
from django.http import HttpResponse
from django.contrib.auth.models import User, Group
from django.contrib.auth import authenticate
from django.http import Http404
from django.utils import timezone
from models import *
from api import *
from django.utils import simplejson
...
# REST endpoint for user registration
# Enforces server-side mediation (input validation)
# On failure, raises Http404
# On success, redirects to registration success page
def register_user(request):
if request.method != 'POST':
raise Http404('Only POSTs are allowed')
# acquire params
username = request.POST['username']
password = request.POST['password']
repeatpw = request.POST['repeatpw']
first_name = request.POST['first_name']
last_name = request.POST['last_name']
# Server-side mediation to check for invalid input
if username == '' or username is None:
raise Http404('Server-side mediation: Invalid Username')
if len(username) > 30:
raise Http404('Server-side mediation: username must be 30 characters or fewer')
if len(first_name) > 30:
raise Http404('Server-side mediation: first name must be 30 characters or fewer')
if len(last_name) > 30:
raise Http404('Server-side mediation: last name msut be 30 characters or fewer')
if len(password) < 4:
raise Http404('Server-side mediation: Password too short')
if password != repeatpw:
raise Http404('Server-side mediation: Password Mismatch')
# This try-except block checks existence of username conflict
try:
test_user_exists = User.objects.get(username__exact=username)
if test_user_exists != None:
raise Http404('Server-side mediation: Username exists')
except User.DoesNotExist:
pass
# Input passes all tests, proceed with user creation
user = User.objects.create_user(username, 'default#nomail.com', password)
group = Group.objects.get(name='Standard')
user.first_name = first_name
user.last_name = last_name
user.groups.add(group)
user.is_staff = False
user.save()
# Build confirmation JSON
confirmation = {
'action': 'register_user',
'username': username,
'success': 'yes',
}
json_return = simplejson.dumps(confirmation)
# return JSON of the success confirmation
return HttpResponse(json_return, mimetype='application/json')

Django-Social-Auth Errors

Update
I tried replacing everything in my custom manager with the following:
def create_user(self, username, email):
return self.model._default_manager.create(username=username)
And that throws an error. I then tried returning the User from my custom user manager and I get 'Cannot assign "": "UserSocialAuth.user" must be a "Barbuser" instance.' thrown from associate_user. It comes from the bowels of django.db.models.fields.related.py. Basically, I'm stuck with knowing how to correctly create users from my custom model mgr. I was going directly off of the docs which lead me to copying everything from django's built in ModelManager. Help?
Update
I'm having trouble configuring django-social-auth. I've been at this for 3-4 days and I'm getting ready to throw in the towel. I have a working existing user registration app installed and I then installed and followed along with the docs on django-social-auth github site. I added the following to my settings.py
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'polls',
'barbuser',
'social_auth',
)
AUTHENTICATION_BACKENDS = (
'social_auth.backends.facebook.FacebookBackend',
'django.contrib.auth.backends.ModelBackend',
)
FACEBOOK_APP_ID = os.environ.get('FACEBOOK_APP_ID')
FACEBOOK_API_SECRET = os.environ.get('FACEBOOK_SECRET')
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'social_auth.context_processors.social_auth_by_type_backends',
)
#SOCIAL_AUTH_ENABLED_BACKENDS = ('facebook',)
SOCIAL_AUTH_DEFAULT_USERNAME = 'new_social_auth_user'
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/profile/'
LOGIN_ERROR_URL = '/login-error/'
SOCIAL_AUTH_USER_MODEL = 'barbuser.Barbuser'
My models.py looks like:
from datetime import date
from django.db import models
from django.contrib.auth.models import User
from django.db.models import BooleanField
from django.db.models.fields import DateTimeField
from django.utils import timezone
from django.utils.crypto import get_random_string
class BarbuserManager(models.Manager):
#classmethod
def normalize_email(cls, email):
"""
Normalize the address by converting the domain part of the email address to lowercase.
"""
email = email or ''
try:
email_name, domain_part = email.strip().rsplit('#', 1)
except ValueError:
pass
else:
email = '#'.join([email_name, domain_part.lower()])
return email
def create_user(self, username, email=None, password=None):
"""
Creates and saves a User with the given username, email and password.
"""
email = 'you#email.com' if email.strip() == '' else email
now = timezone.now()
if not username:
raise ValueError('The given username must be set')
email = BarbuserManager.normalize_email(email)
user = User(username=username, email=email,
is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_joined=now)
user.set_password(password)
user.save()
barbuser = Barbuser(user=user, birthday=date.today(), last_login=user.last_login, name=username)
barbuser.save()
return barbuser
def create_superuser(self, username, email, password):
u = self.create_user(username, email, password)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
def make_random_password(self, length=10,
allowed_chars='abcdefghjkmnpqrstuvwxyz'
'ABCDEFGHJKLMNPQRSTUVWXYZ'
'23456789'):
""" Generates a random password with the given length and given allowed_chars. Note that the default value of allowed_chars does not have "I" or "O" or letters and digits that look similar -- just to avoid confusion. """
return get_random_string(length, allowed_chars)
def get_by_natural_key(self, username):
return self.get(username=username)
class Barbuser(models.Model):
user = models.OneToOneField(User)
username = models.CharField(max_length=200)
last_login = DateTimeField(blank=True)
is_active = BooleanField(default=True)
birthday = models.DateField()
name = models.CharField(max_length=200)
objects = BarbuserManager()
def __init__(self, *args, **kwargs):
me = super(Barbuser, self).__init__(*args, **kwargs)
barbuser = me
return me
def __unicode__(self):
return self.name
def is_authenticated(self):
return self.user.is_authenticated()
I've updated my urls.py to include 'social_auth.urls' and after authentication the user is redirected to ViewProfile view from my views.py:
# Create your views here.
from barbuser.forms import RegistrationForm, LoginForm
from barbuser.models import Barbuser
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template.context import RequestContext
def create_Barbuser(form):
user = User.objects.create_user(form.cleaned_data['username'], form.cleaned_data['email'], form.cleaned_data['password'])
user.save()
barbuser = Barbuser(user=user, name=form.cleaned_data['name'], birthday=form.cleaned_data['birthday'])
barbuser.save()
def process_form(form, request_context):
if form.is_valid():
create_Barbuser(form)
return HttpResponseRedirect('/profile/')
else:
return render_to_response('register.html', {'form': form}, context_instance=request_context)
def render_blank_registration_form(request):
'''When the user is not submitting the form, show them the blank registration form.'''
form = RegistrationForm()
context = {'form': form}
return render_to_response('register.html', context, context_instance=RequestContext(request))
def BarbuserRegistration(request):
"""
Handles the registration of new Barbwire users.
"""
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == "POST":
return process_form(RegistrationForm(request.POST), RequestContext(request))
else:
return render_blank_registration_form(request)
def LoginRequest(request):
'''
Handles Login requests.
'''
if request.user.is_authenticated():
return HttpResponseRedirect('/profile/')
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
barbuser = authenticate(username=username, password=password)
if barbuser is not None:
login(request, barbuser)
return HttpResponseRedirect('/profile/')
else:
return render_to_response('login.html', {'form' : form}, context_instance=RequestContext(request))
else:
return render_to_response('login.html', {'form' : form}, context_instance=RequestContext(request))
else:
form = LoginForm()
return render_to_response('login.html', {'form' : form}, context_instance=RequestContext(request))
def LoginError(request):
return render_to_response('login.html', {'form' : LoginForm()}, context_instance=RequestContext(request))
def LogoutRequest(request):
logout(request)
return HttpResponseRedirect('/')
def ViewProfile(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/')
else:
return render_to_response('profile.html',{'barbuser' : request.user.barbuser }, context_instance=RequestContext(request))
My problem is 2-fold. When I add this extra stuff in my models.py:
def facebook_extra_values(sender, user, response, details, **kwargs):
return False
from social_auth.signals import pre_update
from social_auth.backends.facebook import FacebookBackend
pre_update.connect(facebook_extra_values, sender=FacebookBackend)
I get errors on server startup: assert isinstance(to, basestring), "%s(%r) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string %r" % (self.class._name_, to, RECURSIVE_RELATIONSHIP_CONSTANT)
AssertionError: ForeignKey(None) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
When I remove it I can go thru the login with facebook flow but I get: AttributeError at /complete/facebook/
'NoneType' object has no attribute 'extra_data'
I'm not sure what I'm missing or where I've gone wrong. could somebody help explain where I'm going wrong?
Update
I've traced the problem in debug and apparently I'm getting an IntegrityError in social_auth.backends.pipeline.social.py in the associate_user function when it tries "UserSocialAuth.objects.create". It then falls back into an Except block that calls social_auth_user() and this function returns None for the social_user. The IntegrityError I'm getting is:
insert or update on table "social_auth_usersocialauth" violates foreign key constraint "social_auth_usersocialauth_user_id_fkey"
DETAIL: Key (user_id)=(17) is not present in table "auth_user".
I'm not familiar enough to know how, where or why to associate a social_user with the user created in my CustomUserManager in my models.py. Also I've removed the facebook_extra_values, extra imports, and the preupdate.connect stuff from the bottom of my models.py since I really don't understand what it does or what it's for. I was merely copying things from the example app trying to fix my first problem with the missing association. Help?
Update
The first problem — the ForeignKey error — is caused by a circular import. The solution is easy and follows convention. Take that signal registering code block at the end of models.py and move it to a new file called barbuser/signals.py. Then in barbuser/__init__.py put the line, from .signals import *
I haven't run your code far enough to get your second error — 'NoneType' object has no attribute 'extra_data' — but I found a couple other issues.
Remove the SOCIAL_AUTH_ENABLED_BACKENDS setting from settings.py. I'm not sure where you got that from, but it's not in the documentation for the current social-auth 0.7.0. It's not in the social_auth code either. Probably an old setting.
You reference a non-existent context processor in settings.py (social_auth_login_redirect). Again, maybe an old function. Make sure you are running the newest social-auth (available through PyPi with pip install django-social-auth). Also, use only the context processors you need, never all of them. (Context processors add variables to the template context. If you aren't using the social_auth variable in your templates then you don't need any of the social-auth context processors.) This is important because two of the processors conflict with each other. From the documentation,
social_auth_backends and social_auth_by_type_backends don't play nice
together.
Make sure you've run ./manage.py syncdb to setup the database for the social-auth Model. If there is no database table for the model, that would cause "UserSocialAuth.objects.create()" to break.
Last thought, Django doesn't like the type of thing you are doing defining your own User Model. It's best to leave auth.User alone and make a UserProfile.
UPDATE
Check your database structure; I suspect the indexes are incorrect. Better yet, just delete the three social_auth_* tables and syncdb again. The UserSocialAuth table has a ForeignKey Constraint to the User Model. It should be mapping "user_id" to "Barbuser.id" but if the table was created before you set the settings.py/SOCIAL_AUTH_USER_MODEL value, then the table will be forever broken because SocialAuth defaulted to Django's Auth.User when the initial SQL was run. Make sense? Anyway, just recreate the tables now that you have Social Auth configured.
Note: Your recent experiment using self.model._default_manager.create() isn't accomplishing anything. "self" is a BarbuserManager; "model" is a Barbuser; "_default_manager" is back to a BarbuserManager. Why? "Barbuser.objects" is the default manager for the Model.
Oh, and you had it correct the first time. BarbuserManager.create_user() needs to return a Barbuser.