I am getting KeyError in my partial pipeline when I try to register with twitter accounts while facebook accounts work fine. This is odd because the same function is working fine with facebook users.
The error message is as below:
KeyError at /myapp/
'partial_pipeline'
at 'myapp_auth_form' and my code is:
settings.py
SOCIAL_AUTH_ENABLED_BACKENDS=('facebook','twitter',)
SOCIAL_AUTH_DEFAULT_USERNAME='new_social_auth_user'
...
TWITTER_CONSUMER_KEY = 'mytwitterconsumerkey'
TWITTER_CONSUMER_SECRET = 'mytwitterconsumersecret'
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
LOGIN_ERROR_URL = '/login-error/'
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.misc.save_status_to_session',
'myapp.pipeline.has_email',
'myapp.pipeline.check_by_email',
'myapp.pipeline.redirect_to_form',
'myapp.pipeline.get_username',
'myapp.pipeline.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details'
)
myapp.pipeline
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from social_auth.models import UserSocialAuth
from registration.models import UserProfile
def has_email(details, user=None, *args, **kwargs):
"""Check if email is provided and ask for it otherwise
"""
if user:
return None
email = details.get('email')
if email:
kwargs['request'].session['saved_email'] = email
else:
session = kwargs['request'].session
email = session.get('saved_email')
if not email:
return HttpResponseRedirect(reverse('myapp_email_form'))
def check_by_email(details, user=None, user_exists=UserSocialAuth.simple_user_exists, *args, **kwargs):
"""Check if there's user with same email address and ask for its password to associate
"""
if user:
return None
session = kwargs['request'].session
email = session.get('saved_email')
if email:
if user_exists(username=email):
return HttpResponseRedirect(reverse('myapp_auth_form'))
def redirect_to_form(*args, **kwargs):
"""Redirect to get password if user is None
"""
session = kwargs['request'].session
if not session.get('saved_password') and not session.get('saved_nickname') and not session.get('saved_sex') and kwargs.get('user') is None:
return HttpResponseRedirect(reverse('social_auth_form'))
def get_username(details, user=None, *args, **kwargs):
"""Return an username for new user. Return current user username
if user was given.
Returns email address since myapp uses email for username
"""
if user:
return {'username': user.username}
username = details.get('email') or ''
return {'username': username}
def create_user(backend, details, response, uid, username, user=None, *args, **kwargs):
"""Create user and user profile. Depends on get_username pipeline."""
if user:
return {'user': user}
if not username:
return None
request = kwargs['request']
password = request.session.get('saved_password') or ''
user = UserSocialAuth.create_user(username=username, email=username, password=password)
nickname = request.session.get('saved_nickname') or ''
sex = request.session.get('saved_sex') or 'F'
profile = UserProfile.objects.create(user = user, nickname = nickname, sex = sex)
referee_nickname = request.session.get('saved_referee') or False
# if there was a recommender
if referee_nickname:
try:
referee_profile = UserProfile.objects.get(nickname=referee_nickname)
profile.referee = referee_profile.user
profile.save()
except UserProfile.DoesNotExist:
pass
return {
'user': user,
'is_new': True
}
views.py
from social_auth.utils import setting
from django.contrib.auth import authenticate, login
def myapp_email_form(request):
# if user is logged in already, redirect the user to home
if request.user.is_authenticated():
if request.GET.get('mobile', False):
return HttpResponseRedirect(reverse('m_home'))
return HttpResponseRedirect(reverse('home'))
""" If email is unprovided, ask for it
"""
if request.method == 'POST':
form = EmailForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_email'] = email
backend = request.session[name]['backend']
return redirect('socialauth_complete', backend=backend)
else:
form = EmailForm()
email = request.session.get('saved_email') or ''
variables = RequestContext(request, {
'form': form,
'email': email,
})
if request.is_mobile or request.GET.get('mobile', False):
return render_to_response('mobile/registration/social/email_form.html', variables, context_instance=RequestContext(request))
return render_to_response('.../email_form.html', variables, context_instance=RequestContext(request))
def myapp_auth_form(request):
# if user is logged in already, redirect the user to home
if request.user.is_authenticated():
if request.GET.get('mobile', False):
return HttpResponseRedirect(reverse('m_home'))
return HttpResponseRedirect(reverse('home'))
""" If user's email is already registered to myapp, ask user for its password
"""
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
email = form.cleaned_data['username']
user = authenticate(username=email, password=form.cleaned_data['password'])
if user is not None:
if user.is_active:
login(request, user)
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_user'] = user
############################################
backend = request.session[name]['backend'] #<- I'm getting the KeyError at this point
############################################
return redirect('socialauth_complete', backend=backend)
else:
return HttpResponseRedirect(reverse('inactive_user'))
else:
form.non_field_errors = _('A user with such email and password does not exist.')
else:
form = LoginForm()
email = request.session.get('saved_email') or ''
variables = RequestContext(request, {
'form': form,
'email': email,
})
if request.is_mobile or request.GET.get('mobile', False):
return render_to_response('mobile/registration/social/auth_form.html', variables, context_instance=RequestContext(request))
return render_to_response('.../auth_form.html', variables, context_instance=RequestContext(request))
def social_auth_form(request):
# if user is logged in already, redirect the user to home
if request.user.is_authenticated():
if request.GET.get('mobile', False):
return HttpResponseRedirect(reverse('m_home'))
return HttpResponseRedirect(reverse('home'))
""" Remedy form taking missing information during social authentication
"""
nickname = ''
sex = 'F'
if request.method == 'POST':
form = SocialRegistrationForm(request.POST)
if form.is_valid():
nickname = form.cleaned_data['nickname']
sex = form.cleaned_data['sex']
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_nickname'] = nickname
request.session['saved_sex'] = sex
request.session['saved_password'] = form.cleaned_data['password1']
backend = request.session[name]['backend']
return redirect('socialauth_complete', backend=backend)
else:
form = SocialRegistrationForm()
nickname = request.session.get('saved_username') or ''
sex = request.session.get('saved_gender') or 'F'
if sex == 'male':
sex = 'M'
elif sex == 'female':
sex = 'F'
variables = RequestContext(request, {
'form': form,
'nickname': nickname,
'sex': sex,
})
if request.is_mobile or request.GET.get('mobile', False):
return render_to_response('mobile/registration/social/social_form.html', variables, context_instance=RequestContext(request))
return render_to_response('.../auth_form.html', variables, context_instance=RequestContext(request))
You need to add 'social_auth.backends.pipeline.misc.save_status_to_session' before each method that issues a redirect and halts the process. It works with Facebook because Facebook discloses email addresses, but Twitter doesn't. So, add that method before any entry that does a redirect, or call it within the pipeline code before doing the redirect.
(Just posting the comment as an answer so it can be selected)
You get the following error because you are trying to access the session name with this request.session[name]. That format is suppose to use in storing a session. To fix that,
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_user'] = user
############################################
request.session['name'] = name
backend = request.session.get('name') // this is the session format in getting the data
############################################
return redirect('socialauth_complete', backend=backend)
Related
I am building the reset password page, the first page where the users enter his email work fine, he receive the reset password email with success. The problem it with the page where the user actually write his new password.
When I click on the link / go to the page it give me this error:
assert uidb64 is not None and token is not None # checked by URLconf
I am following this docs here: https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/views/
here is my views.py
#sensitive_post_parameters()
#never_cache
def password_reset_confirm(request, uidb64=None, token=None,
template_name='users/password_reset_confirm.html',
token_generator=default_token_generator,
set_password_form=SetPasswordForm,
post_reset_redirect=None,
current_app=None, extra_context=None):
"""
View that checks the hash in a password reset link and presents a
form for entering a new password.
"""
UserModel = get_user_model()
assert uidb64 is not None and token is not None # checked by URLconf
if post_reset_redirect is None:
post_reset_redirect = reverse('password_reset_complete')
else:
post_reset_redirect = resolve_url(post_reset_redirect)
try:
# urlsafe_base64_decode() decodes to bytestring on Python 3
uid = force_text(urlsafe_base64_decode(uidb64))
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
user = None
if user is not None and token_generator.check_token(user, token):
validlink = True
title = ('Enter new password')
if request.method == 'POST':
form = set_password_form(user, request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(post_reset_redirect)
else:
form = set_password_form(user)
else:
validlink = False
form = None
title = ('Password reset unsuccessful')
context = {
'form': form,
'title': title,
'validlink': validlink,
}
if extra_context is not None:
context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
here is my urls.py
urlpatterns = [
path('password_reset/', views.password_reset, name='password_reset'),
path('password_reset/done/', views.password_reset_done, name="password_reset_done"),
path('reset/MTU/set-password/', views.password_reset_confirm, name="password_reset_confirm")
]
I am working on a project and i am not using the default django user model instead i am using my own custom user model. but i am experiencing a problem. For my user model i have also made my own authb.py file which i have provided below and if i am using the default django authentication then it is authenticating only my superuser and not the user that i am entering through the sign up form and i am totally stuck.
first here is my authb.py
from .models import User
class AuthB:
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(username=username)
return user
except:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except:
return None
but right now i am not using this authb instead i am using default authentication.
here is my models.py for user model
class User(models.Model):
is_authenticated = True
username = models.CharField(max_length= 25)
email = models.CharField(max_length= 150)
password = models.CharField(max_length= 100)
last_login = models.DateTimeField(auto_now= True)
profilepic = models.CharField(max_length= 255, default= "")
def __str__(self):
return self.username
here is my views.py file
def signup(request):
# context = {}
# return render(request, 'sign-up.html', context)
if request.method == 'POST':
# print(request.POST)
# Get form values
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
# Check if passwords match
# Check Username
if User.objects.filter(username=username).exists():
return redirect('signup')
else:
if User.objects.filter(email=email).exists():
return redirect('signup')
else:
u = User.objects.create_user(username=username, password=password, email=email)
u.save()
return redirect('login')
else:
return render(request, 'sign-up.html')
def login(request):
# context = {}
# return render(request, 'index.html', context)
if request.method =='POST':
# print(request.POST)
email = request.POST['email']
password = request.POST['password']
u= auth.authenticate(email=email, password=password)
return redirect('index')
else:
return render(request, 'login.html')
The main problem is that simple user is not able to login in my website only admin are able to login and django i not authenticating my simple user.
I made a clean_email function in my forms.py to check if the email the person is signing up with is part of a registered school.
This is the form:
class StudentRegister(UserCreationForm):
email = forms.EmailField(required = True)
def __init__(self, *args, **kwargs):
super(StudentRegister, self).__init__(*args, **kwargs)
self.fields['email'].widget.attrs['placeholder'] = 'example#example.com'
self.fields['first_name'].widget.attrs['placeholder'] = 'First Name'
self.fields['last_name'].widget.attrs['placeholder'] = 'Last Name'
self.fields['password1'].widget.attrs['placeholder'] = 'Password'
self.fields['password2'].widget.attrs['placeholder'] = 'Password'
class Meta:
model = get_user_model()
fields = (
'email',
'first_name',
'last_name',
'password1',
'password2'
)
def clean_email(self):
email = self.cleaned_data.get('email')
email = email.split('#')[1]
try:
school = School.objects.get(email_domain = email)
except ObjectDoesNotExist:
raise forms.ValidationError('School not found, check your email')
return email
def save(self):
user = super(StudentRegister, self).save()
student = Student(user = user)
student.save()
return user, student
This is the view for the student registration:
def student_registration(request):
#Student Registration
if request.method == 'POST':
form = StudentRegister(request.POST)
#Gets school object from email domain.
email = form['email'].value().split('#')[1]
try:
school = School.objects.get(email_domain = email)
except ObjectDoesNotExist:
pass
if form.is_valid() and school:
user, Student = form.save()
Student.school = school
Student.save()
user.groups.add(Group.objects.get(name='Student'))
#user.is_active to stop users logging in without confirming their emails
user.is_active = False
user.save()
#Sends confirmation link.
send_confirmation_email(request, user)
args = {'email': user.email,
'link': user.Student.school.email_website,}
return render(request, 'email/token_sent.html', args)
else:
args = {'form': form,}
return render(request, 'users/students.html', args)
else:
form = StudentRegister()
args = {'form': form,}
return render(request, 'users/students.html', args)
The error that appears on the form is "Enter a valid email address." even if I enter in a valid email.
Any ideas what the problem may be?
In clean_email method you override original email with domain. Change yout code to this:
def clean_email(self):
original_email = self.cleaned_data.get('email')
email = original_email.split('#')[1]
try:
school = School.objects.get(email_domain = email)
except ObjectDoesNotExist:
raise forms.ValidationError('School not found, check your email')
return original_email
hi i a working on a project for that i have made login and registration of a user. now i want to show full profile of user.since get_profile is not working anymore so how can i get full profile of a user
my models.py
class Consultants(models.Model):
consul_id=models.IntegerField(default=0,primary_key=True)
first_name=models.CharField(max_length=255,blank=True,null=True)
last_name=models.CharField(max_length=255,blank=True,null=True)
email=models.EmailField(max_length=255,blank=True,null=True)
username=models.CharField(max_length=255,blank=True,null=True)
password=models.CharField(max_length=50,blank=True,null=True)
last_login=models.DateTimeField(default=datetime.now,blank=True,null=True)
is_active=models.BooleanField(default=False)
def __str__(self):
return self.first_name
views.py for login and registration
def register(request):
context = RequestContext(request)
registered = False
if request.method == 'POST':
# user_form = UserForm(data=request.POST)
consultant_form = ConsultantsForm(data=request.POST)
if consultant_form.is_valid():
consultant = consultant_form.save(commit=False)
consultant.save()
registered = True
else:
print consultant_form.errors
else:
consultant_form = ConsultantsForm()
return render_to_response(
'register.html',
{'consultant_form': consultant_form, 'registered': registered},
context_instance=RequestContext(request))
def login_user(request):
context = RequestContext(request)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
print type(username)
print "username",username
try:
user = Consultants.objects.get(Q(username= username) & Q(password= password))
print 'chala'
if user.is_active:
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
return HttpResponse("welcome......you are succesfuly log in")
else:
return HttpResponse("Your UkKonnect account is disabled.")
except ObjectDoesNotExist:
return HttpResponse("INvalid User")
else:
return render_to_response('login.html', {}, context)
i want to make def full_profile and def edit_profile.
How can i get logged in user consul_id??
please help me
Not sure that I understand you problem well.. Take a look at recommended way of extending User model:
https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
Then you can do:
u = User.objects.get(username='fsmith')
freds_department = u.employee.department
In your case it would be:
class Consultant(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
*your fields here*
Now you can use standard authentication forms and methods
You always can obtain consultant data as:
request.user.consultant
I'm trying to get my userPass field to be hashed with PBKDF2PasswordHasher upon successful submission and when submitted to check if the userNm field, already exists or not.
I have a modelform:
class RegistrationForm(ModelForm):
userPass = forms.CharField(widget=forms.PasswordInput, label='Password')
class Meta:
model = Client
fields = ['userNm','userPass']
def clean_RegForm(self):
cleanedUserName = self.cleaned_data.get('userNm')
if Client.objects.filter(userNm=cleanedUserName).exists():
errorMsg = u"Error occurred."
raise ValidationError(errorMsg)
else:
return cleanedUserName
a hasher.py file to define a custom definition for PBKDF2PasswordHasher:
from django.contrib.auth.hashers import PBKDF2PasswordHasher
class PBKDF2PasswordHasher(PBKDF2PasswordHasher):
iterations = PBKDF2PasswordHasher.iterations * 100
a view
def Registration(request):
RegForm = RegistrationForm(request.POST or None)
if request.method == 'POST':
if RegForm.is_valid():
clearUserName = RegForm.cleaned_data['userNm']
clearPassNoHash = RegForm.cleaned_data['userPass']
clearPass = make_password(clearPassNoHash.encode("utf-8"),bcrypt.gensalt(14))
RegForm.save()
try:
return HttpResponseRedirect('/Newuser/?userNm=' + clearUserName)
except:
raise ValidationError(('Invalid request'), code='300') ## [ TODO ]: add a custom error page here.
else:
RegForm = RegistrationForm()
return render(request, 'reuse/register.html', {
'RegForm': RegForm
})
settings.py has:
PASSWORD_HASHERS = (
'MyApp.hashers.MyPBKDF2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
)
It currently outputs the userNm on the next page, and saves both userNm and userPass to database, but the userPass is cleartext.
What am I doing wrong here? can someone help?