encripted in reset password
This commit is contained in:
parent
f62348dcdb
commit
bd84dbc3bb
|
@ -17,7 +17,7 @@ Including another URLconf
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from django.urls import path, reverse_lazy
|
from django.urls import path, reverse_lazy
|
||||||
from .views import LoginView
|
from .views import LoginView, PasswordResetConfirmView
|
||||||
from .admin import views as views_admin
|
from .admin import views as views_admin
|
||||||
from .user import views as views_user
|
from .user import views as views_user
|
||||||
|
|
||||||
|
@ -44,13 +44,16 @@ urlpatterns = [
|
||||||
),
|
),
|
||||||
name='password_reset_done'
|
name='password_reset_done'
|
||||||
),
|
),
|
||||||
path('auth/reset/<uidb64>/<token>/',
|
path('auth/reset/<uidb64>/<token>/', PasswordResetConfirmView.as_view(),
|
||||||
auth_views.PasswordResetConfirmView.as_view(
|
|
||||||
template_name='auth/password_reset_confirm.html',
|
|
||||||
success_url=reverse_lazy('idhub:password_reset_complete')
|
|
||||||
),
|
|
||||||
name='password_reset_confirm'
|
name='password_reset_confirm'
|
||||||
),
|
),
|
||||||
|
# path('auth/reset/<uidb64>/<token>/',
|
||||||
|
# auth_views.PasswordResetConfirmView.as_view(
|
||||||
|
# template_name='auth/password_reset_confirm.html',
|
||||||
|
# success_url=reverse_lazy('idhub:password_reset_complete')
|
||||||
|
# ),
|
||||||
|
# name='password_reset_confirm'
|
||||||
|
# ),
|
||||||
path('auth/reset/done/',
|
path('auth/reset/done/',
|
||||||
auth_views.PasswordResetCompleteView.as_view(
|
auth_views.PasswordResetCompleteView.as_view(
|
||||||
template_name='auth/password_reset_complete.html'
|
template_name='auth/password_reset_complete.html'
|
||||||
|
|
|
@ -4,7 +4,6 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.contrib.auth import login as auth_login
|
from django.contrib.auth import login as auth_login
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from nacl import secret
|
|
||||||
|
|
||||||
|
|
||||||
class LoginView(auth_views.LoginView):
|
class LoginView(auth_views.LoginView):
|
||||||
|
@ -23,7 +22,7 @@ class LoginView(auth_views.LoginView):
|
||||||
user = form.get_user()
|
user = form.get_user()
|
||||||
# Decrypt the user's sensitive data encryption key and store it in the session.
|
# Decrypt the user's sensitive data encryption key and store it in the session.
|
||||||
password = form.cleaned_data.get("password")
|
password = form.cleaned_data.get("password")
|
||||||
sensitive_data_encryption_key = user.decrypt_sensitive_data_encryption_key(password)
|
sensitive_data_encryption_key = user.decrypt_sensitive_data(password)
|
||||||
key_dids = cache.get("KEY_DIDS", {})
|
key_dids = cache.get("KEY_DIDS", {})
|
||||||
if not user.is_anonymous and user.is_admin:
|
if not user.is_anonymous and user.is_admin:
|
||||||
user_dashboard = reverse_lazy('idhub:user_dashboard')
|
user_dashboard = reverse_lazy('idhub:user_dashboard')
|
||||||
|
@ -41,3 +40,14 @@ class LoginView(auth_views.LoginView):
|
||||||
|
|
||||||
return HttpResponseRedirect(self.extra_context['success_url'])
|
return HttpResponseRedirect(self.extra_context['success_url'])
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
|
||||||
|
template_name = 'auth/password_reset_confirm.html'
|
||||||
|
success_url = reverse_lazy('idhub:password_reset_complete')
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
password = form.cleaned_data.get("password")
|
||||||
|
user = form.get_user()
|
||||||
|
user.set_encrypted_sensitive_data(password)
|
||||||
|
user.save()
|
||||||
|
return HttpResponseRedirect(self.success_url)
|
||||||
|
|
|
@ -2,7 +2,7 @@ import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from idhub_auth.models import User
|
from idhub_auth.models import User, gen_salt
|
||||||
|
|
||||||
|
|
||||||
class ProfileForm(forms.ModelForm):
|
class ProfileForm(forms.ModelForm):
|
||||||
|
@ -31,4 +31,3 @@ class ProfileForm(forms.ModelForm):
|
||||||
|
|
||||||
return last_name
|
return last_name
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import nacl
|
||||||
|
import base64
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.cache import cache
|
||||||
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
|
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
|
||||||
from nacl import secret, pwhash
|
|
||||||
|
|
||||||
|
|
||||||
class UserManager(BaseUserManager):
|
class UserManager(BaseUserManager):
|
||||||
|
@ -44,10 +47,8 @@ class User(AbstractBaseUser):
|
||||||
is_admin = models.BooleanField(default=False)
|
is_admin = models.BooleanField(default=False)
|
||||||
first_name = models.CharField(max_length=255, blank=True, null=True)
|
first_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
last_name = models.CharField(max_length=255, blank=True, null=True)
|
last_name = models.CharField(max_length=255, blank=True, null=True)
|
||||||
# TODO: Hay que generar una clave aleatoria para cada usuario cuando se le da de alta en el sistema.
|
encrypted_sensitive_data = models.CharField(max_length=255)
|
||||||
encrypted_sensitive_data_encryption_key = models.BinaryField(max_length=255)
|
salt = models.CharField(max_length=255)
|
||||||
# TODO: Hay que generar un salt aleatorio para cada usuario cuando se le da de alta en el sistema.
|
|
||||||
salt_of_sensitive_data_encryption_key = models.BinaryField(max_length=255)
|
|
||||||
|
|
||||||
objects = UserManager()
|
objects = UserManager()
|
||||||
|
|
||||||
|
@ -92,14 +93,54 @@ class User(AbstractBaseUser):
|
||||||
return ", ".join(set(roles))
|
return ", ".join(set(roles))
|
||||||
|
|
||||||
def derive_key_from_password(self, password):
|
def derive_key_from_password(self, password):
|
||||||
kdf = pwhash.argon2i.kdf # TODO: Move the KDF choice to SETTINGS.PY
|
kdf = nacl.pwhash.argon2i.kdf
|
||||||
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE # TODO: Move the KDF choice to SETTINGS.PY
|
ops = nacl.pwhash.argon2i.OPSLIMIT_INTERACTIVE
|
||||||
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE # TODO: Move the KDF choice to SETTINGS.PY
|
mem = nacl.pwhash.argon2i.MEMLIMIT_INTERACTIVE
|
||||||
salt = self.salt_of_sensitive_data_encryption_key
|
return kdf(
|
||||||
return kdf(secret.SecretBox.KEY_SIZE, password, salt, opslimit=ops, memlimit=mem)
|
nacl.secret.SecretBox.KEY_SIZE,
|
||||||
|
password,
|
||||||
|
self.get_salt(),
|
||||||
|
opslimit=ops,
|
||||||
|
memlimit=mem
|
||||||
|
)
|
||||||
|
|
||||||
|
def decrypt_sensitive_data(self, password, data=None):
|
||||||
|
sb_key = self.derive_key_from_password(password.encode('utf-8'))
|
||||||
|
sb = nacl.secret.SecretBox(sb_key)
|
||||||
|
if not data:
|
||||||
|
data = self.get_encrypted_sensitive_data()
|
||||||
|
if not isinstance(data, bytes):
|
||||||
|
data = data.encode('utf-8')
|
||||||
|
|
||||||
|
return sb.decrypt(data).decode('utf-8')
|
||||||
|
|
||||||
|
def encrypt_sensitive_data(self, password, data):
|
||||||
|
sb_key = self.derive_key_from_password(password.encode('utf-8'))
|
||||||
|
sb = nacl.secret.SecretBox(sb_key)
|
||||||
|
if not isinstance(data, bytes):
|
||||||
|
data = data.encode('utf-8')
|
||||||
|
|
||||||
|
return sb.encrypt(data).decode('utf-8')
|
||||||
|
|
||||||
|
def get_salt(self):
|
||||||
|
return base64.b64decode(self.salt.encode('utf-8'))
|
||||||
|
|
||||||
|
def set_salt(self):
|
||||||
|
self.salt = base64.b64encode(nacl.utils.random(16)).decode('utf-8')
|
||||||
|
|
||||||
|
def get_encrypted_sensitive_data(self):
|
||||||
|
return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8'))
|
||||||
|
|
||||||
|
def set_encrypted_sensitive_data(self, password):
|
||||||
|
key = base64.b64encode(nacl.utils.random(64))
|
||||||
|
key_dids = cache.get("KEY_DIDS", {})
|
||||||
|
|
||||||
|
if key_dids.get(user.id):
|
||||||
|
key = key_dids[user.id]
|
||||||
|
else:
|
||||||
|
self.set_salt()
|
||||||
|
|
||||||
|
key_crypted = self.encrypt_sensitive_data(password, key)
|
||||||
|
self.encrypted_sensitive_data = base64.b64encode(key_crypted).decode('utf-8')
|
||||||
|
|
||||||
def decrypt_sensitive_data_encryption_key(self, password):
|
|
||||||
sb_key = self.derive_key_from_password(password)
|
|
||||||
sb = secret.SecretBox(sb_key)
|
|
||||||
return sb.decrypt(self.encrypted_sensitive_data_encryption_key)
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue