mirror of
https://git.linux-kernel.at/oliver/ivatar.git
synced 2025-11-11 18:56:23 +00:00
Merge branch 'oidc' into 'devel'
Add support for OIDC authentication with Fedora See merge request oliver/ivatar!242
This commit is contained in:
@@ -60,13 +60,14 @@ repos:
|
|||||||
rev: v1.12.1
|
rev: v1.12.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: blacken-docs
|
- id: blacken-docs
|
||||||
- repo: https://github.com/hcodes/yaspeller.git
|
# YASpeller does not seem to work anymore
|
||||||
rev: v8.0.1
|
# - repo: https://github.com/hcodes/yaspeller.git
|
||||||
hooks:
|
# rev: v8.0.1
|
||||||
- id: yaspeller
|
# hooks:
|
||||||
|
# - id: yaspeller
|
||||||
types:
|
#
|
||||||
- markdown
|
# types:
|
||||||
|
# - markdown
|
||||||
- repo: https://github.com/kadrach/pre-commit-gitlabci-lint
|
- repo: https://github.com/kadrach/pre-commit-gitlabci-lint
|
||||||
rev: 22d0495c9894e8b27cc37c2ed5d9a6b46385a44c
|
rev: 22d0495c9894e8b27cc37c2ed5d9a6b46385a44c
|
||||||
hooks:
|
hooks:
|
||||||
|
|||||||
29
INSTALL.md
29
INSTALL.md
@@ -19,19 +19,19 @@ sudo apt-get install git python3-virtualenv libmariadb-dev libldap2-dev libsasl2
|
|||||||
|
|
||||||
## Checkout
|
## Checkout
|
||||||
|
|
||||||
~~~~bash
|
```bash
|
||||||
git clone https://git.linux-kernel.at/oliver/ivatar.git
|
git clone https://git.linux-kernel.at/oliver/ivatar.git
|
||||||
cd ivatar
|
cd ivatar
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
## Virtual environment
|
## Virtual environment
|
||||||
|
|
||||||
~~~~bash
|
```bash
|
||||||
virtualenv -p python3 .virtualenv
|
virtualenv -p python3 .virtualenv
|
||||||
source .virtualenv/bin/activate
|
source .virtualenv/bin/activate
|
||||||
pip install pillow
|
pip install pillow
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
~~~~
|
```
|
||||||
|
|
||||||
## (SQL) Migrations
|
## (SQL) Migrations
|
||||||
|
|
||||||
@@ -58,10 +58,27 @@ pip install -r requirements.txt
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Running the testsuite
|
## Running the testsuite
|
||||||
|
|
||||||
```
|
```
|
||||||
./manage.py test -v3 # Or any other verbosity level you like
|
./manage.py test -v3 # Or any other verbosity level you like
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## OpenID Connect authentication with Fedora
|
||||||
|
|
||||||
|
To enable OpenID Connect (OIDC) authentication with Fedora, you must have obtained a `client_id` and `client_secret` pair from the Fedora Infrastructure.
|
||||||
|
Then you must set these values in `config_local.py`:
|
||||||
|
|
||||||
|
```
|
||||||
|
SOCIAL_AUTH_FEDORA_KEY = "the-client-id"
|
||||||
|
SOCIAL_AUTH_FEDORA_SECRET = "the-client-secret"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can override the location of the OIDC provider with the `SOCIAL_AUTH_FEDORA_OIDC_ENDPOINT` setting. For example, to authenticate with Fedora's staging environment, set this in `config_local.py`:
|
||||||
|
|
||||||
|
```
|
||||||
|
SOCIAL_AUTH_FEDORA_OIDC_ENDPOINT = "https://id.stg.fedoraproject.org"
|
||||||
|
```
|
||||||
|
|
||||||
# Production deployment Webserver (non-cloudy)
|
# Production deployment Webserver (non-cloudy)
|
||||||
|
|
||||||
To deploy this Django application with WSGI on Apache, NGINX or any other web server, please refer to the the webserver documentation; There are also plenty of howtos on the net (I'll not LMGTFY...)
|
To deploy this Django application with WSGI on Apache, NGINX or any other web server, please refer to the the webserver documentation; There are also plenty of howtos on the net (I'll not LMGTFY...)
|
||||||
@@ -82,4 +99,4 @@ There is a file called ebcreate.txt as well as a directory called .ebextensions,
|
|||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
It should work with SQLite (do *not* use in production!), MySQL/MariaDB, as well as PostgreSQL.
|
It should work with SQLite (do _not_ use in production!), MySQL/MariaDB, as well as PostgreSQL.
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ AUTHENTICATION_BACKENDS = (
|
|||||||
# See INSTALL for more information.
|
# See INSTALL for more information.
|
||||||
# 'django_auth_ldap.backend.LDAPBackend',
|
# 'django_auth_ldap.backend.LDAPBackend',
|
||||||
"django_openid_auth.auth.OpenIDBackend",
|
"django_openid_auth.auth.OpenIDBackend",
|
||||||
|
"ivatar.ivataraccount.auth.FedoraOpenIdConnect",
|
||||||
"django.contrib.auth.backends.ModelBackend",
|
"django.contrib.auth.backends.ModelBackend",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,6 +59,10 @@ TEMPLATES[0]["OPTIONS"]["context_processors"].append(
|
|||||||
|
|
||||||
OPENID_CREATE_USERS = True
|
OPENID_CREATE_USERS = True
|
||||||
OPENID_UPDATE_DETAILS_FROM_SREG = True
|
OPENID_UPDATE_DETAILS_FROM_SREG = True
|
||||||
|
SOCIAL_AUTH_JSONFIELD_ENABLED = True
|
||||||
|
# Fedora authentication (OIDC). You need to set these two values to use it.
|
||||||
|
SOCIAL_AUTH_FEDORA_KEY = None # Also known as client_id
|
||||||
|
SOCIAL_AUTH_FEDORA_SECRET = None # Also known as client_secret
|
||||||
|
|
||||||
SITE_NAME = os.environ.get("SITE_NAME", "libravatar")
|
SITE_NAME = os.environ.get("SITE_NAME", "libravatar")
|
||||||
IVATAR_VERSION = "1.8.0"
|
IVATAR_VERSION = "1.8.0"
|
||||||
|
|||||||
56
ivatar/ivataraccount/auth.py
Normal file
56
ivatar/ivataraccount/auth.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from social_core.backends.open_id_connect import OpenIdConnectAuth
|
||||||
|
|
||||||
|
from ivatar.ivataraccount.models import ConfirmedEmail, Photo
|
||||||
|
from ivatar.settings import logger, TRUST_EMAIL_FROM_SOCIAL_AUTH_BACKENDS
|
||||||
|
|
||||||
|
|
||||||
|
class FedoraOpenIdConnect(OpenIdConnectAuth):
|
||||||
|
name = "fedora"
|
||||||
|
USERNAME_KEY = "nickname"
|
||||||
|
OIDC_ENDPOINT = "https://id.fedoraproject.org"
|
||||||
|
DEFAULT_SCOPE = ["openid", "profile", "email"]
|
||||||
|
TOKEN_ENDPOINT_AUTH_METHOD = "client_secret_post"
|
||||||
|
|
||||||
|
|
||||||
|
# Pipeline methods
|
||||||
|
|
||||||
|
|
||||||
|
def add_confirmed_email(backend, user, response, *args, **kwargs):
|
||||||
|
"""Add a ConfirmedEmail if we trust the auth backend to validate email."""
|
||||||
|
if not kwargs.get("is_new", False):
|
||||||
|
return None # Only act on account creation
|
||||||
|
if backend.name not in TRUST_EMAIL_FROM_SOCIAL_AUTH_BACKENDS:
|
||||||
|
return None
|
||||||
|
if ConfirmedEmail.objects.filter(email=user.email).count() > 0:
|
||||||
|
# email already exists
|
||||||
|
return None
|
||||||
|
(confirmed_id, external_photos) = ConfirmedEmail.objects.create_confirmed_email(
|
||||||
|
user, user.email, True
|
||||||
|
)
|
||||||
|
confirmed_email = ConfirmedEmail.objects.get(id=confirmed_id)
|
||||||
|
logger.debug(
|
||||||
|
"Email %s added upon creation of user %s", confirmed_email.email, user.pk
|
||||||
|
)
|
||||||
|
photo = Photo.objects.create(user=user, ip_address=confirmed_email.ip_address)
|
||||||
|
import_result = photo.import_image("Gravatar", confirmed_email.email)
|
||||||
|
if import_result:
|
||||||
|
logger.debug("Gravatar image imported for %s", confirmed_email.email)
|
||||||
|
|
||||||
|
|
||||||
|
def associate_by_confirmed_email(backend, details, user=None, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Associate current auth with a user that has their email address as ConfirmedEmail in the DB.
|
||||||
|
"""
|
||||||
|
if user:
|
||||||
|
return None
|
||||||
|
email = details.get("email")
|
||||||
|
if not email:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
confirmed_email = ConfirmedEmail.objects.get(email=email)
|
||||||
|
except ConfirmedEmail.DoesNotExist:
|
||||||
|
return None
|
||||||
|
user = confirmed_email.user
|
||||||
|
logger.debug("Found a matching ConfirmedEmail for %s upon login", user.username)
|
||||||
|
return {"user": user, "is_new": False}
|
||||||
@@ -32,6 +32,10 @@
|
|||||||
<button type="submit" class="button">{% trans 'Login' %}</button>
|
<button type="submit" class="button">{% trans 'Login' %}</button>
|
||||||
|
|
||||||
<a href="{% url 'openid-login' %}" class="button">{% trans 'Login with OpenID' %}</a>
|
<a href="{% url 'openid-login' %}" class="button">{% trans 'Login with OpenID' %}</a>
|
||||||
|
{% if with_fedora %}
|
||||||
|
|
||||||
|
<a href="{% url "social:begin" "fedora" %}" class="button">{% trans 'Login with Fedora' %}</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<a href="{% url 'new_account' %}" class="button">{% trans 'Create new user' %}</a>
|
<a href="{% url 'new_account' %}" class="button">{% trans 'Create new user' %}</a>
|
||||||
|
|
||||||
|
|||||||
73
ivatar/ivataraccount/test_auth.py
Normal file
73
ivatar/ivataraccount/test_auth.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from ivatar.ivataraccount.auth import FedoraOpenIdConnect
|
||||||
|
from ivatar.ivataraccount.models import ConfirmedEmail
|
||||||
|
from django.test import override_settings
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(SOCIAL_AUTH_FEDORA_OIDC_ENDPOINT="https://id.example.com/")
|
||||||
|
class AuthFedoraTestCase(TestCase):
|
||||||
|
def _authenticate(self, response):
|
||||||
|
backend = FedoraOpenIdConnect()
|
||||||
|
pipeline = backend.strategy.get_pipeline(backend)
|
||||||
|
return backend.pipeline(pipeline, response=response)
|
||||||
|
|
||||||
|
def test_new_user(self):
|
||||||
|
"""Check that a Fedora user gets a ConfirmedEmail automatically."""
|
||||||
|
user = self._authenticate({"nickname": "testuser", "email": "test@example.com"})
|
||||||
|
self.assertEqual(user.confirmedemail_set.count(), 1)
|
||||||
|
self.assertEqual(user.confirmedemail_set.first().email, "test@example.com")
|
||||||
|
|
||||||
|
@mock.patch("ivatar.ivataraccount.auth.TRUST_EMAIL_FROM_SOCIAL_AUTH_BACKENDS", [])
|
||||||
|
def test_new_user_untrusted_backend(self):
|
||||||
|
"""Check that ConfirmedEmails aren't automatically created for untrusted backends."""
|
||||||
|
user = self._authenticate({"nickname": "testuser", "email": "test@example.com"})
|
||||||
|
self.assertEqual(user.confirmedemail_set.count(), 0)
|
||||||
|
|
||||||
|
def test_existing_user(self):
|
||||||
|
"""Checks that existing users are found."""
|
||||||
|
user = User.objects.create_user(
|
||||||
|
username="testuser",
|
||||||
|
password="password",
|
||||||
|
email="test@example.com",
|
||||||
|
first_name="test",
|
||||||
|
last_name="user",
|
||||||
|
)
|
||||||
|
auth_user = self._authenticate(
|
||||||
|
{"nickname": "testuser", "email": "test@example.com"}
|
||||||
|
)
|
||||||
|
self.assertEqual(auth_user, user)
|
||||||
|
# Only add ConfirmedEmails on account creation.
|
||||||
|
self.assertEqual(auth_user.confirmedemail_set.count(), 0)
|
||||||
|
|
||||||
|
def test_existing_user_with_confirmed_email(self):
|
||||||
|
"""Check that the authenticating user is found using their ConfirmedEmail."""
|
||||||
|
user = User.objects.create_user(
|
||||||
|
username="testuser1",
|
||||||
|
password="password",
|
||||||
|
email="first@example.com",
|
||||||
|
first_name="test",
|
||||||
|
last_name="user",
|
||||||
|
)
|
||||||
|
ConfirmedEmail.objects.create_confirmed_email(user, "second@example.com", False)
|
||||||
|
auth_user = self._authenticate(
|
||||||
|
{"nickname": "testuser2", "email": "second@example.com"}
|
||||||
|
)
|
||||||
|
self.assertEqual(auth_user, user)
|
||||||
|
|
||||||
|
def test_existing_confirmed_email(self):
|
||||||
|
"""Check that ConfirmedEmail isn't created twice."""
|
||||||
|
user = User.objects.create_user(
|
||||||
|
username="testuser",
|
||||||
|
password="password",
|
||||||
|
email="testuser@example.com",
|
||||||
|
first_name="test",
|
||||||
|
last_name="user",
|
||||||
|
)
|
||||||
|
ConfirmedEmail.objects.create_confirmed_email(user, user.email, False)
|
||||||
|
auth_user = self._authenticate({"nickname": user.username, "email": user.email})
|
||||||
|
self.assertEqual(auth_user, user)
|
||||||
|
self.assertEqual(auth_user.confirmedemail_set.count(), 1)
|
||||||
@@ -8,6 +8,7 @@ import contextlib
|
|||||||
# pylint: disable=too-many-lines
|
# pylint: disable=too-many-lines
|
||||||
from urllib.parse import urlsplit
|
from urllib.parse import urlsplit
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from contextlib import suppress
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import gzip
|
import gzip
|
||||||
@@ -16,8 +17,10 @@ import base64
|
|||||||
import django
|
import django
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test import Client
|
from django.test import Client
|
||||||
|
from django.test import override_settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
from django.core.cache import caches
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
import hashlib
|
import hashlib
|
||||||
@@ -40,6 +43,7 @@ from ivatar.utils import random_string
|
|||||||
TEST_IMAGE_FILE = os.path.join(settings.STATIC_ROOT, "img", "deadbeef.png")
|
TEST_IMAGE_FILE = os.path.join(settings.STATIC_ROOT, "img", "deadbeef.png")
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings()
|
||||||
class Tester(TestCase): # pylint: disable=too-many-public-methods
|
class Tester(TestCase): # pylint: disable=too-many-public-methods
|
||||||
"""
|
"""
|
||||||
Main test class
|
Main test class
|
||||||
@@ -49,7 +53,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
|||||||
user = None
|
user = None
|
||||||
username = random_string()
|
username = random_string()
|
||||||
password = random_string()
|
password = random_string()
|
||||||
email = "%s@%s.%s" % (username, random_string(), random_string(2))
|
email = "%s@%s.org" % (username, random_string())
|
||||||
# Dunno why random tld doesn't work, but I'm too lazy now to investigate
|
# Dunno why random tld doesn't work, but I'm too lazy now to investigate
|
||||||
openid = "http://%s.%s.%s/" % (username, random_string(), "org")
|
openid = "http://%s.%s.%s/" % (username, random_string(), "org")
|
||||||
first_name = random_string()
|
first_name = random_string()
|
||||||
@@ -72,6 +76,14 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
|||||||
first_name=self.first_name,
|
first_name=self.first_name,
|
||||||
last_name=self.last_name,
|
last_name=self.last_name,
|
||||||
)
|
)
|
||||||
|
# Disable caching
|
||||||
|
settings.CACHES["default"] = {
|
||||||
|
"BACKEND": "django.core.cache.backends.dummy.DummyCache",
|
||||||
|
}
|
||||||
|
caches._settings = None
|
||||||
|
with suppress(AttributeError):
|
||||||
|
# clear the existing cache connection
|
||||||
|
delattr(caches._connections, "default")
|
||||||
|
|
||||||
def test_new_user(self):
|
def test_new_user(self):
|
||||||
"""
|
"""
|
||||||
@@ -454,7 +466,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
|||||||
)
|
)
|
||||||
|
|
||||||
for i in range(max_num_unconfirmed + 1):
|
for i in range(max_num_unconfirmed + 1):
|
||||||
response = self.client.post(
|
response = self.client.post( # noqa: F841
|
||||||
reverse("add_email"),
|
reverse("add_email"),
|
||||||
{
|
{
|
||||||
"email": "%i.%s" % (i, self.email),
|
"email": "%i.%s" % (i, self.email),
|
||||||
@@ -475,7 +487,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
|||||||
settings.EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
|
settings.EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"
|
||||||
|
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
response = self.client.post(
|
response = self.client.post( # noqa: F841
|
||||||
reverse("add_email"),
|
reverse("add_email"),
|
||||||
{
|
{
|
||||||
"email": self.email,
|
"email": self.email,
|
||||||
@@ -494,7 +506,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
|||||||
# Should set EMAIL_BACKEND, so no need to do it here
|
# Should set EMAIL_BACKEND, so no need to do it here
|
||||||
self.test_confirm_email()
|
self.test_confirm_email()
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post( # noqa: F841
|
||||||
reverse("add_email"),
|
reverse("add_email"),
|
||||||
{
|
{
|
||||||
"email": self.email,
|
"email": self.email,
|
||||||
@@ -521,7 +533,7 @@ class Tester(TestCase): # pylint: disable=too-many-public-methods
|
|||||||
confirmedemail.user = otheruser
|
confirmedemail.user = otheruser
|
||||||
confirmedemail.save()
|
confirmedemail.save()
|
||||||
|
|
||||||
response = self.client.post(
|
response = self.client.post( # noqa: F841
|
||||||
reverse("add_email"),
|
reverse("add_email"),
|
||||||
{
|
{
|
||||||
"email": self.email,
|
"email": self.email,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ from ivatar.settings import (
|
|||||||
MAX_PHOTO_SIZE,
|
MAX_PHOTO_SIZE,
|
||||||
JPEG_QUALITY,
|
JPEG_QUALITY,
|
||||||
AVATAR_MAX_SIZE,
|
AVATAR_MAX_SIZE,
|
||||||
|
SOCIAL_AUTH_FEDORA_KEY,
|
||||||
)
|
)
|
||||||
from .gravatar import get_photo as get_gravatar_photo
|
from .gravatar import get_photo as get_gravatar_photo
|
||||||
|
|
||||||
@@ -1099,6 +1100,11 @@ class IvatarLoginView(LoginView):
|
|||||||
return HttpResponseRedirect(reverse_lazy("profile"))
|
return HttpResponseRedirect(reverse_lazy("profile"))
|
||||||
return super().get(self, request, args, kwargs)
|
return super().get(self, request, args, kwargs)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["with_fedora"] = SOCIAL_AUTH_FEDORA_KEY is not None
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(login_required, name="dispatch")
|
@method_decorator(login_required, name="dispatch")
|
||||||
class ProfileView(TemplateView):
|
class ProfileView(TemplateView):
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ INSTALLED_APPS = [
|
|||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
|
"social_django",
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -59,6 +60,7 @@ TEMPLATES = [
|
|||||||
"django.contrib.auth.context_processors.auth",
|
"django.contrib.auth.context_processors.auth",
|
||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
"django.template.context_processors.i18n",
|
"django.template.context_processors.i18n",
|
||||||
|
"social_django.context_processors.login_redirect",
|
||||||
],
|
],
|
||||||
"debug": DEBUG,
|
"debug": DEBUG,
|
||||||
},
|
},
|
||||||
@@ -122,6 +124,50 @@ if not DEBUG:
|
|||||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||||
SECURE_HSTS_PRELOAD = True
|
SECURE_HSTS_PRELOAD = True
|
||||||
|
|
||||||
|
|
||||||
|
# Social authentication
|
||||||
|
TRUST_EMAIL_FROM_SOCIAL_AUTH_BACKENDS = ["fedora"]
|
||||||
|
SOCIAL_AUTH_PIPELINE = (
|
||||||
|
# Get the information we can about the user and return it in a simple
|
||||||
|
# format to create the user instance later. In some cases the details are
|
||||||
|
# already part of the auth response from the provider, but sometimes this
|
||||||
|
# could hit a provider API.
|
||||||
|
"social_core.pipeline.social_auth.social_details",
|
||||||
|
# Get the social uid from whichever service we're authing thru. The uid is
|
||||||
|
# the unique identifier of the given user in the provider.
|
||||||
|
"social_core.pipeline.social_auth.social_uid",
|
||||||
|
# Verifies that the current auth process is valid within the current
|
||||||
|
# project, this is where emails and domains whitelists are applied (if
|
||||||
|
# defined).
|
||||||
|
"social_core.pipeline.social_auth.auth_allowed",
|
||||||
|
# Checks if the current social-account is already associated in the site.
|
||||||
|
"social_core.pipeline.social_auth.social_user",
|
||||||
|
# Make up a username for this person, appends a random string at the end if
|
||||||
|
# there's any collision.
|
||||||
|
"social_core.pipeline.user.get_username",
|
||||||
|
# Send a validation email to the user to verify its email address.
|
||||||
|
# Disabled by default.
|
||||||
|
# 'social_core.pipeline.mail.mail_validation',
|
||||||
|
# Associates the current social details with another user account with
|
||||||
|
# a similar email address. Disabled by default.
|
||||||
|
"social_core.pipeline.social_auth.associate_by_email",
|
||||||
|
# Associates the current social details with an existing user account with
|
||||||
|
# a matching ConfirmedEmail.
|
||||||
|
"ivatar.ivataraccount.auth.associate_by_confirmed_email",
|
||||||
|
# Create a user account if we haven't found one yet.
|
||||||
|
"social_core.pipeline.user.create_user",
|
||||||
|
# Create the record that associates the social account with the user.
|
||||||
|
"social_core.pipeline.social_auth.associate_user",
|
||||||
|
# Populate the extra_data field in the social record with the values
|
||||||
|
# specified by settings (and the default ones like access_token, etc).
|
||||||
|
"social_core.pipeline.social_auth.load_extra_data",
|
||||||
|
# Update the user record with any changed info from the auth service.
|
||||||
|
"social_core.pipeline.user.user_details",
|
||||||
|
# Create the ConfirmedEmail if appropriate.
|
||||||
|
"ivatar.ivataraccount.auth.add_confirmed_email",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/2.0/topics/i18n/
|
# https://docs.djangoproject.com/en/2.0/topics/i18n/
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ urlpatterns = [ # pylint: disable=invalid-name
|
|||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path("i18n/", include("django.conf.urls.i18n")),
|
path("i18n/", include("django.conf.urls.i18n")),
|
||||||
path("openid/", include("django_openid_auth.urls")),
|
path("openid/", include("django_openid_auth.urls")),
|
||||||
|
path("auth/", include("social_django.urls", namespace="social")),
|
||||||
path("tools/", include("ivatar.tools.urls")),
|
path("tools/", include("ivatar.tools.urls")),
|
||||||
re_path(
|
re_path(
|
||||||
r"avatar/(?P<digest>\w{64})", AvatarImageView.as_view(), name="avatar_view"
|
r"avatar/(?P<digest>\w{64})", AvatarImageView.as_view(), name="avatar_view"
|
||||||
|
|||||||
Reference in New Issue
Block a user