Skip to content

Commit

Permalink
Add social account login capability (#994) (#995)
Browse files Browse the repository at this point in the history
* Add settings and urls

* Login template

* Update requirements.txt

* Add setting fo socialaccount

* Add pre_social_login signal receiver

* Fix connect user socialaccount

* Update base settings

* Update settings

* Management fo role and backend of user logged by socialaccount

* Update requirements.txt

* Typo

* Add ACCOUNT_EMAIL_VERIFICATION = 'none'

* Change login backend order

---------

Co-authored-by: wlorenzetti <[email protected]>
(cherry picked from commit d62c141)

Co-authored-by: Walter Lorenzetti <[email protected]>
  • Loading branch information
github-actions[bot] and wlorenzetti authored Dec 18, 2024
1 parent 37f1226 commit e729dbf
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 48 deletions.
40 changes: 27 additions & 13 deletions g3w-admin/base/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.gis',
#'django.contrib.sites',
'django.contrib.sites',
]

THIRD_PARTY_APPS = [
Expand All @@ -75,7 +75,13 @@
'about',
'django_bleach',
'django_registration',
'captcha'
'captcha',
"allauth",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.microsoft",
"allauth.socialaccount.providers.google",
"allauth.usersessions"
]

G3WADMIN_APPS = [
Expand Down Expand Up @@ -104,6 +110,10 @@
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware',
'qdjango.process_events_middleware.process_events_middleware',

# Allauth middleware
'allauth.account.middleware.AccountMiddleware',
'allauth.usersessions.middleware.UserSessionsMiddleware'
]


Expand All @@ -127,10 +137,6 @@
'loaders': [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader'
#('django.template.loaders.cached.Loader', [
# 'django.template.loaders.filesystem.Loader',
# 'django.template.loaders.app_directories.Loader'
#]),
],
},
},
Expand All @@ -142,7 +148,6 @@
ATOMIC_REQUESTS = True

# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
Expand All @@ -162,6 +167,7 @@
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'guardian.backends.ObjectPermissionBackend',
'allauth.account.auth_backends.AuthenticationBackend'
)

GUARDIAN_RAISE_403 = True
Expand Down Expand Up @@ -241,8 +247,6 @@


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/

STATIC_URL = '/static/'

SITE_TITLE = 'g3w-admin'
Expand All @@ -252,7 +256,7 @@
QDJANGO_PRJ_CACHE = True
QDJANGO_PRJ_CACHE_KEY = 'qdjango_prj_'

# data for proxy server
# Data for proxy server
PROXY_SERVER = False

# LOGGING_CONFIG = None
Expand Down Expand Up @@ -303,7 +307,6 @@

SITE_ID = 1


INTERNAL_IPS = [
'127.0.0.1',
]
Expand Down Expand Up @@ -344,7 +347,6 @@

# QPLOTLY DEFAULT SETTINGS
# ------------------------

LOAD_QPLOTLY_FROM_PROJECT = False

# VENDOR KEYS SETTINGS
Expand Down Expand Up @@ -387,4 +389,16 @@
# Settings for ReCaptcha v2. Default checkbox
RECAPTCHA_VERSION2_TYPE = 'checkbox' # or 'invisible'

SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']
SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']

# SOCIAL ACCOUNT LOGIN SETTINGS
# -----------------------------
SOCIALACCOUNT_LOGIN_ON_GET = True
SOCIALACCOUNT_ADAPTER = 'usersmanage.vendors.allauth.adapter.G3WSocialAccountAdapter'

# Activate/deactivate user login session tracking
USERSESSIONS_TRACK_ACTIVITY = False

SOCIALACCOUNT_ONLY = True
SOCIALACCOUNT_USER_ROLE = 'Viewer Level 1'
ACCOUNT_EMAIL_VERIFICATION = 'none'
4 changes: 4 additions & 0 deletions g3w-admin/base/settings/local_settings_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,7 @@
'worker_type': 'process',
},
}

# For social login
# Activate/deactivate user login session tracking
USERSESSIONS_TRACK_ACTIVITY = False
3 changes: 3 additions & 0 deletions g3w-admin/base/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,11 @@
),
name="django_registration_disallowed",
),
path('allauthg/', include('allauth.urls')),
]



#############################################################
# PASSWORD RESET (user password reset by email)
# USERNAME RECOVERY (username recovery by email)
Expand Down
72 changes: 39 additions & 33 deletions g3w-admin/templates/login.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "base_login.html" %}
{% load socialaccount %}
{% load static %}
{% load i18n %}

Expand All @@ -22,42 +23,47 @@ <h4><i class="icon fa fa-ban"></i> {% trans 'LOGIN ERROR' %}!</h4>
{% trans 'Username and/or password uncorrect' %}
</div>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="form-group has-feedback">
<input type="text" class="form-control" name="username" placeholder="Username">
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
<div class="form-group has-feedback">
<input type="password" class="form-control" name="password" placeholder="Password">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
<div class="form-group recaptcha">{{ form.captcha }}</div>
<div class="row margin-bottom" >
<div class="col-xs-12">
<button type="submit" class="btn btn-primary btn-block btn-flat">{% trans 'Sign In' %}</button>
</div><!-- /.col -->
</div>
{% if SETTINGS.RESET_USER_PASSWORD %}
<div class="row">
<div class="col-xs-12">
<a href="{% url 'password_reset' %}">{% trans 'Forgot your password?' %}</a>
<form method="post">
{% csrf_token %}
<div class="form-group has-feedback">
<input type="text" class="form-control" name="username" placeholder="Username">
<span class="glyphicon glyphicon-user form-control-feedback"></span>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<a href="{% url 'username_recovery' %}">{% trans 'Forgot your username?' %}</a>
<div class="form-group has-feedback">
<input type="password" class="form-control" name="password" placeholder="Password">
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div>
</div>
{% endif %}
{% if SETTINGS.REGISTRATION_OPEN %}
<div class="row">
<div class="col-xs-12">
<a href="{% url 'django_registration_register' %}">{% trans 'Sign up' %}</a>
<div class="form-group recaptcha">{{ form.captcha }}</div>
<div class="row margin-bottom" >
<div class="col-xs-12">
<button type="submit" class="btn btn-primary btn-block btn-flat">{% trans 'Sign In' %}</button>
</div><!-- /.col -->
</div>
</div>
{% endif %}
</form>

<div class="row">
{% include "socialaccount/provider_list.html" with process="login" %}
</div>

{% if SETTINGS.RESET_USER_PASSWORD %}
<div class="row">
<div class="col-xs-12">
<a class="btn btn-info btn-block btn-flat" href="{% url 'password_reset' %}">{% trans 'Forgot your password?' %}</a>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<a class="btn btn-info btn-block btn-flat margin-bottom-small" href="{% url 'username_recovery' %}">{% trans 'Forgot your username?' %}</a>
</div>
</div>
{% endif %}
{% if SETTINGS.REGISTRATION_OPEN %}
<div class="row">
<div class="col-xs-12">
<a class="btn btn-info btn-block btn-flat margin-bottom-small" href="{% url 'django_registration_register' %}">{% trans 'Sign up' %}</a>
</div>
</div>
{% endif %}
</form>
</div><!-- /.login-box-body -->
{% include 'include/login_page_version.html' %}
</div><!-- /.login-box -->
Expand Down
2 changes: 2 additions & 0 deletions g3w-admin/usersmanage/receivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,5 @@ def send_email_to_user(sender, **kwargs):
)

user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL, fail_silently=True)


22 changes: 22 additions & 0 deletions g3w-admin/usersmanage/templates/socialaccount/provider_list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{% load allauth socialaccount %}
{% load i18n %}
{% get_providers as socialaccount_providers %}
{% if socialaccount_providers %}
<div class="col-xs-12" style="text-align: center;">
<p>- {% trans 'OR' %} -</p>
</div>
{% for provider in socialaccount_providers %}
{% if provider.id == "openid" %}
{% for brand in provider.get_brands %}
{% provider_login_url provider openid=brand.openid_url process=process as href %}
{% element provider name=brand.name provider_id=provider.id href=href %}
{% endelement %}
{% endfor %}
{% endif %}
{% provider_login_url provider process=process scope=scope auth_params=auth_params as href %}
<div class="col-xs-12">
<a class="btn btn-default btn-block btn-flat" href="{{ href }}">{{ provider.name }}</a>
</div>
{% endfor %}
<div class="col-xs-12" style="margin-bottom: 20px;"></div>
{% endif %}
Empty file.
Empty file.
58 changes: 58 additions & 0 deletions g3w-admin/usersmanage/vendors/allauth/adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# coding=utf-8
""""
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the Mozilla Public License 2.0.
"""

__author__ = '[email protected]'
__date__ = '2024-12-17'
__copyright__ = 'Copyright 2015 - 2024, Gis3w'
__license__ = 'MPL 2.0'

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
from allauth.account.models import EmailAddress
from usersmanage.models import User, Group as AuthGroup, Userbackend, USER_BACKEND_DEFAULT
from usersmanage.configs import G3W_EDITOR1, G3W_EDITOR2, G3W_VIEWER1

class G3WSocialAccountAdapter(DefaultSocialAccountAdapter):

def _set_user_role_backend(self, user):
"""
Set the role and the backend for the user login by social
"""

# Role to se from settings
role = settings.SOCIALACCOUNT_USER_ROLE \
if settings.SOCIALACCOUNT_USER_ROLE in (G3W_EDITOR1, G3W_EDITOR2, G3W_VIEWER1) else G3W_VIEWER1

AuthGroup.objects.get(name=role).user_set.add(user)

# Backend
if not hasattr(user, 'userbackend'):
Userbackend(user=user, backend=USER_BACKEND_DEFAULT).save()

def pre_social_login(self, request, sociallogin):

# Social account already exists, so this is just a login
if sociallogin.is_existing:
return

# some social logins don't have an email address
if not sociallogin.email_addresses:
return
try:
existing_user = User.objects.get(email=sociallogin.email_addresses[0].email)
self._set_user_role_backend(existing_user)
except ObjectDoesNotExist:
return

# if it does, connect this new social login to the existing user
sociallogin.connect(request, existing_user)

def save_user(self, request, sociallogin, form=None):
user = super(G3WSocialAccountAdapter, self).save_user(request, sociallogin, form=form)
self._set_user_role_backend(user)
return user
6 changes: 4 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ django-ordered-model==3.3.0
django-ajax-selects==2.2.0
django-modeltranslation==0.17.5
django-filter
django-bleach
django-bleach==3.0.1
pathlib2
lxml
psycopg2-binary
Expand All @@ -30,7 +30,7 @@ django-import-export==3.2.0
coverage
urllib3
python-magic
celery==4.4.7
celery #==5.0.2
deprecation
huey==2.4.3
redis==4.5.4
Expand All @@ -40,3 +40,5 @@ django-recaptcha==3.0.0
pydantic==2.6.3
weasyprint==63.0
distro==1.7.0
django-allauth[socialaccount]==0.63.6

0 comments on commit e729dbf

Please sign in to comment.