Changed model definitions and added logic to decrypt and set user key in session storage
This commit is contained in:
parent
5eb606c4a4
commit
37dc8335a7
|
@ -6,6 +6,8 @@ from django.db import models
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from nacl import secret
|
||||||
|
|
||||||
from utils.idhub_ssikit import (
|
from utils.idhub_ssikit import (
|
||||||
generate_did_controller_key,
|
generate_did_controller_key,
|
||||||
keydid_from_controller_key,
|
keydid_from_controller_key,
|
||||||
|
@ -409,7 +411,9 @@ class DID(models.Model):
|
||||||
# In JWK format. Must be stored as-is and passed whole to library functions.
|
# In JWK format. Must be stored as-is and passed whole to library functions.
|
||||||
# Example key material:
|
# Example key material:
|
||||||
# '{"kty":"OKP","crv":"Ed25519","x":"oB2cPGFx5FX4dtS1Rtep8ac6B__61HAP_RtSzJdPxqs","d":"OJw80T1CtcqV0hUcZdcI-vYNBN1dlubrLaJa0_se_gU"}'
|
# '{"kty":"OKP","crv":"Ed25519","x":"oB2cPGFx5FX4dtS1Rtep8ac6B__61HAP_RtSzJdPxqs","d":"OJw80T1CtcqV0hUcZdcI-vYNBN1dlubrLaJa0_se_gU"}'
|
||||||
key_material = models.CharField(max_length=250)
|
# CHANGED: `key_material` to `_key_material`, datatype from CharField to BinaryField and the key is now stored encrypted.
|
||||||
|
key_material = None
|
||||||
|
_key_material = models.BinaryField(max_length=250)
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
User,
|
User,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
|
@ -417,6 +421,18 @@ class DID(models.Model):
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_key_material(self, session):
|
||||||
|
if "sensitive_data_encryption_key" not in session:
|
||||||
|
raise Exception("Ojo! Se intenta acceder a datos cifrados sin tener la clave de usuario.")
|
||||||
|
sb = secret.SecretBox(session["sensitive_data_encryption_key"])
|
||||||
|
return sb.decrypt(self._key_material)
|
||||||
|
|
||||||
|
def set_key_material(self, value, session):
|
||||||
|
if "sensitive_data_encryption_key" not in session:
|
||||||
|
raise Exception("Ojo! Se intenta acceder a datos cifrados sin tener la clave de usuario.")
|
||||||
|
sb = secret.SecretBox(session["sensitive_data_encryption_key"])
|
||||||
|
self._key_material = sb.encrypt(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_organization_did(self):
|
def is_organization_did(self):
|
||||||
if not self.user:
|
if not self.user:
|
||||||
|
@ -427,7 +443,8 @@ class DID(models.Model):
|
||||||
self.key_material = generate_did_controller_key()
|
self.key_material = generate_did_controller_key()
|
||||||
self.did = keydid_from_controller_key(self.key_material)
|
self.did = keydid_from_controller_key(self.key_material)
|
||||||
|
|
||||||
def get_key(self):
|
# TODO: darmengo: esta funcion solo se llama desde un fichero que sube cosas a s3 (??) Preguntar a ver que hace.
|
||||||
|
def get_key_deprecated(self):
|
||||||
return json.loads(self.key_material)
|
return json.loads(self.key_material)
|
||||||
|
|
||||||
|
|
||||||
|
@ -464,7 +481,10 @@ class VerificableCredential(models.Model):
|
||||||
created_on = models.DateTimeField(auto_now=True)
|
created_on = models.DateTimeField(auto_now=True)
|
||||||
issued_on = models.DateTimeField(null=True)
|
issued_on = models.DateTimeField(null=True)
|
||||||
subject_did = models.CharField(max_length=250)
|
subject_did = models.CharField(max_length=250)
|
||||||
data = models.TextField()
|
# CHANGED: `data` to `_data`, datatype from TextField to BinaryField and the rendered VC is now stored encrypted.
|
||||||
|
# TODO: verify that BinaryField can hold arbitrary amounts of data (max_length = ???)
|
||||||
|
data = None
|
||||||
|
_data = models.BinaryField()
|
||||||
csv_data = models.TextField()
|
csv_data = models.TextField()
|
||||||
status = models.PositiveSmallIntegerField(
|
status = models.PositiveSmallIntegerField(
|
||||||
choices=Status.choices,
|
choices=Status.choices,
|
||||||
|
@ -486,6 +506,18 @@ class VerificableCredential(models.Model):
|
||||||
related_name='vcredentials',
|
related_name='vcredentials',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_data(self, session):
|
||||||
|
if "sensitive_data_encryption_key" not in session:
|
||||||
|
raise Exception("Ojo! Se intenta acceder a datos cifrados sin tener la clave de usuario.")
|
||||||
|
sb = secret.SecretBox(session["sensitive_data_encryption_key"])
|
||||||
|
return sb.decrypt(self._data)
|
||||||
|
|
||||||
|
def set_data(self, value, session):
|
||||||
|
if "sensitive_data_encryption_key" not in session:
|
||||||
|
raise Exception("Ojo! Se intenta acceder a datos cifrados sin tener la clave de usuario.")
|
||||||
|
sb = secret.SecretBox(session["sensitive_data_encryption_key"])
|
||||||
|
self._data = sb.encrypt(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_schema(self):
|
def get_schema(self):
|
||||||
if not self.data:
|
if not self.data:
|
||||||
|
|
|
@ -25,4 +25,8 @@ class LoginView(auth_views.LoginView):
|
||||||
if self.extra_context['success_url'] == user_dashboard:
|
if self.extra_context['success_url'] == user_dashboard:
|
||||||
self.extra_context['success_url'] = admin_dashboard
|
self.extra_context['success_url'] = admin_dashboard
|
||||||
auth_login(self.request, user)
|
auth_login(self.request, user)
|
||||||
|
# Decrypt the user's sensitive data encryption key and store it in the session.
|
||||||
|
password = form.cleaned_data.get("password") # TODO: Is this right????????
|
||||||
|
sensitive_data_encryption_key = user.decrypt_sensitive_data_encryption_key(password)
|
||||||
|
self.request.session["sensitive_data_encryption_key"] = sensitive_data_encryption_key
|
||||||
return HttpResponseRedirect(self.extra_context['success_url'])
|
return HttpResponseRedirect(self.extra_context['success_url'])
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
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):
|
||||||
|
@ -43,6 +44,10 @@ 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_encryption_key = models.BinaryField(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()
|
||||||
|
|
||||||
|
@ -85,3 +90,16 @@ class User(AbstractBaseUser):
|
||||||
for r in s.service.rol.all():
|
for r in s.service.rol.all():
|
||||||
roles.append(r.name)
|
roles.append(r.name)
|
||||||
return ", ".join(set(roles))
|
return ", ".join(set(roles))
|
||||||
|
|
||||||
|
def derive_key_from_password(self, password):
|
||||||
|
kdf = pwhash.argon2i.kdf # TODO: Move the KDF choice to SETTINGS.PY
|
||||||
|
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE # TODO: Move the KDF choice to SETTINGS.PY
|
||||||
|
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE # TODO: Move the KDF choice to SETTINGS.PY
|
||||||
|
salt = self.salt_of_sensitive_data_encryption_key
|
||||||
|
return kdf(secret.SecretBox.KEY_SIZE, password, salt, opslimit=ops, memlimit=mem)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,4 @@ didkit==0.3.2
|
||||||
jinja2==3.1.2
|
jinja2==3.1.2
|
||||||
jsonref==1.1.0
|
jsonref==1.1.0
|
||||||
pyld==2.0.3
|
pyld==2.0.3
|
||||||
|
pynacl==1.5.0
|
||||||
|
|
Loading…
Reference in New Issue