fix issue dids and credentials

This commit is contained in:
Cayo Puigdefabregas 2024-01-06 19:18:59 +01:00
parent 5dc1577d9e
commit cb9ef0b608
8 changed files with 68 additions and 59 deletions

View File

@ -17,6 +17,7 @@ from django.views.generic.edit import (
UpdateView, UpdateView,
) )
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.core.cache import cache
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.http import HttpResponse from django.http import HttpResponse
from django.contrib import messages from django.contrib import messages
@ -645,13 +646,14 @@ class DidRegisterView(Credentials, CreateView):
def form_valid(self, form): def form_valid(self, form):
form.instance.user = self.request.user form.instance.user = self.request.user
form.instance.set_did() form.instance.set_did(cache.get("KEY_DIDS"))
form.save() form.save()
messages.success(self.request, _('DID created successfully')) messages.success(self.request, _('DID created successfully'))
Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance) Event.set_EV_ORG_DID_CREATED_BY_ADMIN(form.instance)
return super().form_valid(form) return super().form_valid(form)
class DidEditView(Credentials, UpdateView): class DidEditView(Credentials, UpdateView):
template_name = "idhub/admin/did_register.html" template_name = "idhub/admin/did_register.html"
subtitle = _('Organization Identities (DID)') subtitle = _('Organization Identities (DID)')

View File

@ -37,7 +37,6 @@ class Command(BaseCommand):
self.create_organizations(r[0].strip(), r[1].strip()) self.create_organizations(r[0].strip(), r[1].strip())
self.sync_credentials_organizations("pangea.org", "somconnexio.coop") self.sync_credentials_organizations("pangea.org", "somconnexio.coop")
self.sync_credentials_organizations("local 8000", "local 9000") self.sync_credentials_organizations("local 8000", "local 9000")
self.create_defaults_dids()
self.create_schemas() self.create_schemas()
def create_admin_users(self, email, password): def create_admin_users(self, email, password):
@ -47,6 +46,7 @@ class Command(BaseCommand):
key = su.decrypt_sensitive_data(password) key = su.decrypt_sensitive_data(password)
key_dids = {su.id: key} key_dids = {su.id: key}
cache.set("KEY_DIDS", key_dids, None) cache.set("KEY_DIDS", key_dids, None)
self.create_defaults_dids(su, key)
def create_users(self, email, password): def create_users(self, email, password):
@ -54,10 +54,8 @@ class Command(BaseCommand):
u.set_password(password) u.set_password(password)
u.set_encrypted_sensitive_data(password) u.set_encrypted_sensitive_data(password)
u.save() u.save()
key_dids = cache.get("KEY_DIDS", {})
key = u.decrypt_sensitive_data(password) key = u.decrypt_sensitive_data(password)
key_dids.update({u.id: key}) self.create_defaults_dids(u, key)
cache.set("KEY_DIDS", key_dids)
def create_organizations(self, name, url): def create_organizations(self, name, url):
@ -73,10 +71,9 @@ class Command(BaseCommand):
org1.save() org1.save()
org2.save() org2.save()
def create_defaults_dids(self): def create_defaults_dids(self, u, password):
for u in User.objects.all():
did = DID(label="Default", user=u) did = DID(label="Default", user=u)
did.set_did() did.set_did(password)
did.save() did.save()
def create_schemas(self): def create_schemas(self):

View File

@ -3,6 +3,7 @@ import pytz
import datetime import datetime
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
from django.core.cache import cache
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 nacl import secret
@ -419,17 +420,11 @@ class DID(models.Model):
null=True, null=True,
) )
def get_key_material(self): def get_key_material(self, password):
return self.user.decrypt_data(self.key_material) return self.user.decrypt_data(self.key_material, password)
def set_key_material(self, value): def set_key_material(self, value, password):
self.key_material = self.user.encrypt_data(value) self.key_material = self.user.encrypt_data(value, password)
def get_data(self):
return self.user.decrypt_data(self.data)
def set_data(self, value):
self.data = self.user.encrypt_data(value)
@property @property
def is_organization_did(self): def is_organization_did(self):
@ -437,7 +432,7 @@ class DID(models.Model):
return True return True
return False return False
def set_did(self): def set_did(self, password):
""" """
Generates a new DID Controller Key and derives a DID from it. Generates a new DID Controller Key and derives a DID from it.
Because DID Controller Keys are stored encrypted using a User's Sensitive Data Encryption Key, Because DID Controller Keys are stored encrypted using a User's Sensitive Data Encryption Key,
@ -445,12 +440,7 @@ class DID(models.Model):
""" """
new_key_material = generate_did_controller_key() new_key_material = generate_did_controller_key()
self.did = keydid_from_controller_key(new_key_material) self.did = keydid_from_controller_key(new_key_material)
self.set_key_material(new_key_material) self.set_key_material(new_key_material, password)
# 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)
class Schemas(models.Model): class Schemas(models.Model):
@ -514,11 +504,13 @@ class VerificableCredential(models.Model):
related_name='vcredentials', related_name='vcredentials',
) )
def get_data(self): def get_data(self, password):
return self.user.decrypt_data(self.data) if not self.data:
return ""
return self.user.decrypt_data(self.data, password)
def set_data(self, value): def set_data(self, value, password):
self.data = self.user.encrypt_data(value) self.data = self.user.encrypt_data(value, password)
def type(self): def type(self):
return self.schema.type return self.schema.type
@ -536,19 +528,19 @@ class VerificableCredential(models.Model):
data = json.loads(self.csv_data).items() data = json.loads(self.csv_data).items()
return data return data
def issue(self, did): def issue(self, did, password):
if self.status == self.Status.ISSUED: if self.status == self.Status.ISSUED:
return return
# self.status = self.Status.ISSUED self.status = self.Status.ISSUED
import pdb; pdb.set_trace()
self.subject_did = did self.subject_did = did
self.issued_on = datetime.datetime.now().astimezone(pytz.utc) self.issued_on = datetime.datetime.now().astimezone(pytz.utc)
issuer_pass = cache.get("KEY_DIDS")
data = sign_credential( data = sign_credential(
self.render(), self.render(),
self.issuer_did.get_key_material() self.issuer_did.get_key_material(issuer_pass)
) )
self.data = self.user.encrypt_data(data) self.data = self.user.encrypt_data(data, password)
def get_context(self): def get_context(self):
d = json.loads(self.csv_data) d = json.loads(self.csv_data)

View File

@ -22,6 +22,7 @@ class RequestCredentialForm(forms.Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None) self.user = kwargs.pop('user', None)
self.password = kwargs.pop('password', None)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['did'].choices = [ self.fields['did'].choices = [
(x.did, x.label) for x in DID.objects.filter(user=self.user) (x.did, x.label) for x in DID.objects.filter(user=self.user)
@ -49,7 +50,8 @@ class RequestCredentialForm(forms.Form):
did = did[0] did = did[0]
cred = cred[0] cred = cred[0]
try: try:
cred.issue(did) if self.password:
cred.issue(did, self.password)
except Exception: except Exception:
return return

View File

@ -120,7 +120,15 @@ class CredentialJsonView(MyWallet, TemplateView):
pk=pk, pk=pk,
user=self.request.user user=self.request.user
) )
response = HttpResponse(self.object.get_data(), content_type="application/json") pass_enc = self.request.session.get("key_did")
data = ""
if pass_enc:
user_pass = self.request.user.decrypt_data(
pass_enc,
self.request.user.password+self.request.session._session_key
)
data = self.object.get_data(user_pass)
response = HttpResponse(data, content_type="application/json")
response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json") response['Content-Disposition'] = 'attachment; filename={}'.format("credential.json")
return response return response
@ -135,6 +143,15 @@ class CredentialsRequestView(MyWallet, FormView):
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user kwargs['user'] = self.request.user
pass_enc = self.request.session.get("key_did")
if pass_enc:
user_pass = self.request.user.decrypt_data(
pass_enc,
self.request.user.password+self.request.session._session_key
)
else:
pass_enc = None
kwargs['password'] = user_pass
return kwargs return kwargs
def form_valid(self, form): def form_valid(self, form):
@ -205,7 +222,11 @@ class DidRegisterView(MyWallet, CreateView):
def form_valid(self, form): def form_valid(self, form):
form.instance.user = self.request.user form.instance.user = self.request.user
form.instance.set_did() pw = self.request.user.decrypt_data(
self.request.session.get("key_did"),
self.request.user.password+self.request.session._session_key
)
form.instance.set_did(pw)
form.save() form.save()
messages.success(self.request, _('DID created successfully')) messages.success(self.request, _('DID created successfully'))

View File

@ -20,23 +20,23 @@ class LoginView(auth_views.LoginView):
def form_valid(self, form): def form_valid(self, form):
user = form.get_user() user = form.get_user()
# 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")
auth_login(self.request, user)
sensitive_data_encryption_key = user.decrypt_sensitive_data(password) sensitive_data_encryption_key = user.decrypt_sensitive_data(password)
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')
admin_dashboard = reverse_lazy('idhub:admin_dashboard') admin_dashboard = reverse_lazy('idhub:admin_dashboard')
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
key_dids[user.id] = sensitive_data_encryption_key cache.set("KEY_DIDS", sensitive_data_encryption_key, None)
cache.set("KEY_DIDS", key_dids, None)
else:
key_dids[user.id] = sensitive_data_encryption_key
cache.set("KEY_DIDS", key_dids)
auth_login(self.request, user) self.request.session["key_did"] = user.encrypt_data(
sensitive_data_encryption_key,
user.password+self.request.session._session_key
)
return HttpResponseRedirect(self.extra_context['success_url']) return HttpResponseRedirect(self.extra_context['success_url'])

View File

@ -145,24 +145,18 @@ class User(AbstractBaseUser):
key_crypted = self.encrypt_sensitive_data(password, key) key_crypted = self.encrypt_sensitive_data(password, key)
self.encrypted_sensitive_data = key_crypted self.encrypted_sensitive_data = key_crypted
def encrypt_data(self, data): def encrypt_data(self, data, password):
sb = self.get_secret_box() sb = self.get_secret_box(password)
value = base64.b64encode(data.encode('utf-8')) value = base64.b64encode(data.encode('utf-8'))
value_enc = sb.encrypt(data.encode('utf-8')) value_enc = sb.encrypt(data.encode('utf-8'))
return base64.b64encode(value_enc).decode('utf-8') return base64.b64encode(value_enc).decode('utf-8')
def decrypt_data(self, data): def decrypt_data(self, data, password):
sb = self.get_secret_box() sb = self.get_secret_box(password)
value = base64.b64decode(data.encode('utf-8')) value = base64.b64decode(data.encode('utf-8'))
return sb.decrypt(value).decode('utf-8') return sb.decrypt(value).decode('utf-8')
def get_secret_box(self): def get_secret_box(self, password):
key_dids = cache.get("KEY_DIDS", {}) pw = base64.b64decode(password.encode('utf-8'))
if not key_dids.get(self.id):
err = "An attempt is made to access encrypted "
err += "data without having the key."
raise Exception(_(err))
pw = base64.b64decode(key_dids[self.id].encode('utf-8'))
sb_key = self.derive_key_from_password(pw) sb_key = self.derive_key_from_password(pw)
return nacl.secret.SecretBox(sb_key) return nacl.secret.SecretBox(sb_key)

View File

@ -149,6 +149,7 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/ # https://docs.djangoproject.com/en/4.2/topics/i18n/