Add first implementation of the authentication backend
This commit is contained in:
parent
903e55f75e
commit
6da3033fdf
|
@ -3,4 +3,5 @@ include CONTRIBUTING.rst
|
|||
include HISTORY.rst
|
||||
include LICENSE
|
||||
include README.rst
|
||||
include requirements.txt
|
||||
recursive-include django_cryptolock *.html *.png *.gif *js *.css *jpg *jpeg *svg *py
|
||||
|
|
|
@ -1,6 +1,40 @@
|
|||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from monerorpc.authproxy import AuthServiceProxy, JSONRPCException
|
||||
|
||||
from .models import Address
|
||||
from .utils import verify_signature
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class MoneroAddressBackend(ModelBackend):
|
||||
"""Custom Monero-Cryptolock authentication backend."""
|
||||
|
||||
def authenticate(self, request, address=None, challenge=None, signature=None):
|
||||
pass
|
||||
"""Validates the provided signature for the given address and challenge.
|
||||
|
||||
This method currently relies on Wallet RPC access to verify the signature,
|
||||
in the future it should be done locally to be more reliable and more
|
||||
performant.
|
||||
"""
|
||||
if not all(address, challenge, signature):
|
||||
return None
|
||||
|
||||
try:
|
||||
stored_address = Address.objects.get(address=address).select_related("user")
|
||||
except:
|
||||
return None
|
||||
|
||||
try:
|
||||
is_valid = verify_signature(address, challenge, signature)
|
||||
except JSONRPCException:
|
||||
raise PermissionDenied(_("Error while validating signature"))
|
||||
|
||||
if is_valid:
|
||||
return stored_address.user
|
||||
|
||||
return None
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.5 on 2019-10-15 16:41
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('django_cryptolock', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='address',
|
||||
unique_together={('user', 'address')},
|
||||
),
|
||||
]
|
|
@ -20,6 +20,7 @@ class Address(TimeStampedModel):
|
|||
|
||||
verbose_name = _("Address")
|
||||
verbose_name_plural = _("Addresses")
|
||||
unique_together = ["user", "address"]
|
||||
|
||||
def __str__(self):
|
||||
"""Unicode representation of Address."""
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
from django.conf import settings
|
||||
|
||||
from monerorpc.authproxy import AuthServiceProxy
|
||||
|
||||
|
||||
def verify_signature(address: str, challenge: str, signature: str) -> bool:
|
||||
"""Makes a request to wallet RPC to verify address and signature."""
|
||||
protocol = settings.MONERO_WALLET_RPC_PROTOCOL
|
||||
host = settings.MONERO_WALLET_RPC_HOST
|
||||
user = settings.MONERO_WALLET_RPC_USER
|
||||
pwd = settings.MONERO_WALLET_RPC_PASS
|
||||
wallet_rpc = AuthServiceProxy(f"{protocol}://{user}:{pwd}@{host}/json_rpc")
|
||||
|
||||
result = wallet_rpc.verify(
|
||||
{"data": challenge, "address": address, "signature": signature}
|
||||
)
|
||||
|
||||
return result.get("good", False)
|
|
@ -1,3 +1,4 @@
|
|||
django>=2.2
|
||||
django-model-utils>=2.0
|
||||
monero>=0.6
|
||||
python-monerorpc>=0.5.5
|
||||
|
|
|
@ -26,3 +26,7 @@ if django.VERSION >= (1, 10):
|
|||
MIDDLEWARE = ()
|
||||
else:
|
||||
MIDDLEWARE_CLASSES = ()
|
||||
|
||||
MONERO_WALLET_RPC_HOST = "localhost:3030"
|
||||
MONERO_WALLET_RPC_USER = "test"
|
||||
MONERO_WALLET_RPC_PASS = "test"
|
||||
|
|
4
tox.ini
4
tox.ini
|
@ -7,8 +7,8 @@ setenv =
|
|||
PYTHONPATH = {toxinidir}:{toxinidir}/django_cryptolock
|
||||
commands = coverage run --source django_cryptolock runtests.py
|
||||
deps =
|
||||
django-20: Django>=2.2,<3.0
|
||||
-r{toxinidir}/requirements_test.txt
|
||||
django-22: Django>=2.2
|
||||
-r {toxinidir}/requirements_test.txt
|
||||
basepython =
|
||||
py37: python3.7
|
||||
py36: python3.6
|
||||
|
|
Loading…
Reference in New Issue