Manually Invoking email verification - django-allauth

We've been using django-allauth for quite some time now in production. We can enable account email verification which works great. But we now have a REST api that allows users to register through the API and the workflow doesn't go through django-allauth. Is it possible to manually invoke the django-allauth email verification feature or do we need to use a custom solution?

I'll just post my answer here as I've been searching for adding email verification with Django Built-in Authentication (And using a Custom Auth Model), I used the method mentioned by Marcus, I'll just add all the other stuff around it for anyone who wants to do the same.
First: Install django-allauth as described here
Second: Add your email configurations in the settings.py file :
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com' #I used gmail in my case
EMAIL_HOST_USER = <Your Email>
EMAIL_HOST_PASSWORD = <Your Password>
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = <Default Sender name and email>
Third: Add configurations for verification and default login url, you'll find the documentation of all config parameters here, note that in my example I'm using a custom user model as mentioned, that's why I'm setting ACCOUNT_EMAIL_REQUIRED to True & ACCOUNT_USER_MODEL_USERNAME_FIELD and ACCOUNT_USERNAME_REQUIRED to False, also the LOGIN_URL,ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL andLOGIN_REDIRECT_URL parameters are used after the user clicks on the confirmation link sent by email to him
ACCOUNT_EMAIL_VERIFICATION='mandatory'
ACCOUNT_CONFIRM_EMAIL_ON_GET=True
ACCOUNT_EMAIL_REQUIRED=True
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
LOGIN_URL='app:login_user'
LOGIN_REDIRECT_URL='app:login_user'
ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL='app:login_user'
Fourth: After your signup form, save the user instance with is_active parameter set to False, then call the method:
from allauth.account.utils import *
send_email_confirmation(request, user, True)
Finally: Receive the signal after the user confirms his email, and set is_active to True
from allauth.account.signals import email_confirmed
from django.dispatch import receiver
# Signal sent to activate user upon confirmation
#receiver(email_confirmed)
def email_confirmed_(request, email_address, **kwargs):
user = MyUser.objects.get(email=email_address.email)
user.is_active = True
user.save()
Finally, you would want to change the default site name from Django Admin as it will be included in the email sent.

I had the same problem, and the solution I've found was to call the original send_email_confirmation method from allauth. I am using DRF3 for my API.
from allauth.account.utils import send_email_confirmation
...
def some_view(request):
user = ...
...
#using request._request to avoid TypeError on change made in DRF3 (from HTTPRequest to Request object)
send_email_confirmation(request._request, user)
...
I hope this helps you.

Related

django all-auth enable 2FA using email

As per the installation instructions at https://django-allauth-2FA.readthedocs.io/en/latest/ have implemented all steps and have no idea how to enable email based OTP for login for existing users. Even added a manual adapter.py as below:
from allauth.account.adapter import DefaultAccountAdapter
from urllib.parse import urlencode
from allauth.account.adapter import DefaultAccountAdapter
from allauth.exceptions import ImmediateHttpResponse
from django.http import HttpResponseRedirect
from django.urls import reverse
from allauth_2fa.utils import user_has_valid_totp_device
class NoNewUsersAccountAdapter(DefaultAccountAdapter):
"""
Adapter to disable allauth new signups
Used at equilang/settings.py with key ACCOUNT_ADAPTER
https://django-allauth.readthedocs.io/en/latest/advanced.html#custom-redirects """
def is_open_for_signup(self, request):
"""
Checks whether or not the site is open for signups.
Next to simply returning True/False you can also intervene the
regular flow by raising an ImmediateHttpResponse
"""
return False
def has_2fa_enabled(self, user):
"""Returns True if the user has 2FA configured."""
return user_has_valid_totp_device(user)
def login(self, request, user):
# Require two-factor authentication if it has been configured.
if self.has_2fa_enabled(user):
# Cast to string for the case when this is not a JSON serializable
# object, e.g. a UUID.
request.session["allauth_2fa_user_id"] = str(user.id)
redirect_url = reverse("two-factor-authenticate")
# Add "next" parameter to the URL.
view = request.resolver_match.func.view_class()
view.request = request
success_url = view.get_success_url()
query_params = request.GET.copy()
if success_url:
query_params[view.redirect_field_name] = success_url
if query_params:
redirect_url += "?" + urlencode(query_params)
raise ImmediateHttpResponse(response=HttpResponseRedirect(redirect_url))
# Otherwise defer to the original allauth adapter.
return super().login(request, user)
But no OTP's are fired. When I manually created a TOTP device a window appears for asking OTP after login but don't know where and how the email with OTP is sent.
Any help or lead please

Is it possible to have a few passwords in authlogic gem?

Right now we have phone_number as login, and sms code (4 digits) as password.
When user wants to login:
- user enters phone number
- we generate code
- we save code to user password field
- we send code to user via sms
- user uses this sms code to login in
We want to be able to have last 3 generated codes (password) be valid for login:
- we started to save generated codes in separate table
And here is the question: How do I connect this to authlogic? Is the any callback that turns off default password check and give me ability to add my custom logic for password checking?
I found a solution which helped me to tune password validation logic.
My authlogic version 3.5.6 and I has method called validate_by_password in following implementation.
I copied first part of it to save blank fields and logic checks. And overwrote invalid password check in way I need.
class Client::Session < Authlogic::Session::Base
...
def validate_by_password
# copy paste from gem
self.invalid_password = false
# check for blank fields
errors.add(login_field, I18n.t('error_messages.login_blank', default: 'cannot be blank')) if send(login_field).blank?
errors.add(password_field, I18n.t('error_messages.password_blank', default: 'cannot be blank')) if send("protected_#{password_field}").blank?
return if errors.count > 0
# check for unknown login
self.attempted_record = search_for_record(find_by_login_method, send(login_field))
if attempted_record.blank?
generalize_credentials_error_messages? ?
add_general_credentials_error :
errors.add(login_field, I18n.t('error_messages.login_not_found', default: 'is not valid'))
return
end
# custom check for invalid password
...
end
end

Allow user to register using django-all-auth even if the social account exists and then connect the two automatically

So, I have been able to connect social accounts (fb or google) to be connected to the local email account if already exists.
However, I also want the reverse functionality, i.e. I would like to allow user to sign up even if the (google or FB) social account exists. Currently it says:
{ A user is already registered with this email address }
I am using django-all-auth and django-rest-auth with Django 2.1
Yes, you can do that. You should be able to modify the password reset endpoint provided by django-rest-auth to set a password and then be able to login:
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import PasswordResetForm as DjangoPasswordResetForm
from rest_auth.serializers import (
PasswordResetSerializer as RestAuthPasswordResetSerializer
)
from rest_auth.views import PasswordResetView as RestAuthPasswordResetView
UserModel = get_user_model()
class PasswordResetForm(DjangoPasswordResetForm):
def get_users(self, email):
"""
Given an email, return matching user(s) who should receive a reset.
"""
active_users = UserModel._default_manager.filter(**{
'%s__iexact' % UserModel.get_email_field_name(): email,
'is_active': True,
})
return iter(active_users)
# or (u for u in active_users if not u.has_usable_password())
class PasswordResetSerializer(RestAuthPasswordResetSerializer):
password_reset_form_class = PasswordResetForm
class PasswordResetView(RestAuthPasswordResetView):
serializer_class = PasswordResetSerializer
You can add this view to your urls.py as general endpoint to reset passwords (remember to place it in front of the rest_auths' URLs) or as an additional endpoint to set passwords (see the commented line). Then you can add a note to your signup page that links to your page that serves your new endpoint.
As an alternative, you could also add a field to your user settings page where users can set a password.
You could also send an e-mail with a link via send_confirmation to set a password when a user tries to sign up and the e-mail exists already (or only in case this user has a social account). If you like I could add an example here how to do that.

prevent user login after registration using django-allauth

i'm using django-allauth for my django app. by default, when a user successfully sign's up, they are automatically logged in. how do you override the default behaviour and prevent the user from logging in after after successful signup. After the user signs up, he/she must be redirected to the login page. ive disabled email verification. Thank you.
# settings.py
LOGIN_REDIRECT_URL = 'welcome'
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False
ACCOUNT_LOGOUT_REDIRECT_URL = 'thanks'
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
If you don't need the email verification, you can skip the login like this:
First in your urls.py, you must override the url to the default SignupView with a url to your own view:
url(r^'accounts/signup/$', views.CustomSignupView.as_view(), name="account_signup")
Then in your views.py, you have a custom view that will return a path to your frontpage instead of continuing to login the user.
class CustomSignupView(SignupView):
def form_valid(self, form):
self.user = form.save(self.request)
return redirect('/frontpage')

Check Login data in Code

I'm writing an API for my Website. For Auth. i use ZfcUser. Is it possible to check the Login Data?. Like my API get per Post username/email and the password. Now i want to check if the username/email and password are correct. Also i want create a User in Code. But my problem is that the same password in ZfcUser has different hashs. I know that ZfcUser use Bycrypt but i don't know how the Cost is. In ZfcUser i found this Line:
$bcrypt->setCost($this->getOptions()->getPasswordCost());
ZfcUser: https://github.com/ZF-Commons/ZfcUser
mfg ternes3
I have found the solution by my self :D. The default Cost is 10. And it's possible to verify the Password with Bcrypt.
$bycrypt->verify($pass, $passhash);
You get a boolean with this method ;D
The second solution is:
$newUser = new User();
$newUser->user_id = '';
$newUser->email = '';
$password = ''
$bcrypt = new Bcrypt();
$bcrypt->setCost(10);
$newUser->password = $bcrypt->create($password);
$userT->saveUser($newUser);
mfg ternes3

Resources