Merge pull request 'encrypt2' (#145) from encrypt2 into release

Reviewed-on: https://gitea.pangea.org/trustchain-oc1-orchestral/IdHub/pulls/145
This commit is contained in:
cayop 2024-02-22 17:57:10 +00:00
commit 4f562162bf
25 changed files with 370 additions and 218 deletions

View file

@ -1,23 +1,19 @@
import csv
import json import json
import copy
import base64 import base64
import jsonschema import jsonschema
import pandas as pd import pandas as pd
from pyhanko.sign import signers from nacl.exceptions import CryptoError
from django import forms from django import forms
from django.core.cache import cache from django.core.cache import cache
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from utils import credtools, certs from utils import certs
from idhub.models import ( from idhub.models import (
DID, DID,
File_datas, File_datas,
Membership, Membership,
Schemas, Schemas,
Service,
UserRol, UserRol,
VerificableCredential, VerificableCredential,
) )
@ -51,6 +47,38 @@ class TermsConditionsForm2(forms.Form):
return return
class EncryptionKeyForm(forms.Form):
key = forms.CharField(
label=_("Key for encrypt the secrets of all system"),
required=True
)
def clean(self):
data = self.cleaned_data
self._key = data["key"]
if not DID.objects.exists():
return data
did = DID.objects.first()
cache.set("KEY_DIDS", self._key, None)
try:
did.get_key_material()
except CryptoError:
cache.set("KEY_DIDS", None)
txt = _("Key no valid!")
raise ValidationError(txt)
cache.set("KEY_DIDS", None)
return data
def save(self, commit=True):
if commit:
cache.set("KEY_DIDS", self._key, None)
return
class TermsConditionsForm(forms.Form): class TermsConditionsForm(forms.Form):
accept_privacy = forms.BooleanField( accept_privacy = forms.BooleanField(
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}), widget=forms.CheckboxInput(attrs={'class': 'form-check-input'}),
@ -133,7 +161,7 @@ class ImportForm(forms.Form):
self.fields['did'].choices = [ self.fields['did'].choices = [
(x.did, x.label) for x in dids.filter(eidas1=False) (x.did, x.label) for x in dids.filter(eidas1=False)
] ]
self.fields['schema'].choices = [ self.fields['schema'].choices = [(0, _('Select one'))] + [
(x.id, x.name) for x in Schemas.objects.filter() (x.id, x.name) for x in Schemas.objects.filter()
] ]
if dids.filter(eidas1=True).exists(): if dids.filter(eidas1=True).exists():
@ -197,6 +225,9 @@ class ImportForm(forms.Form):
if not data_pd: if not data_pd:
self.exception("This file is empty!") self.exception("This file is empty!")
if not self._schema:
return data
for n in range(df.last_valid_index()+1): for n in range(df.last_valid_index()+1):
row = {} row = {}
for k in data_pd.keys(): for k in data_pd.keys():
@ -226,18 +257,21 @@ class ImportForm(forms.Form):
except jsonschema.exceptions.ValidationError as err: except jsonschema.exceptions.ValidationError as err:
msg = "line {}: {}".format(line+1, err) msg = "line {}: {}".format(line+1, err)
return self.exception(msg) return self.exception(msg)
# try:
# check = credtools.validate_json(row, self.json_schema)
# if check is not True:
# raise ValidationError("Not valid row")
# except Exception as e:
user, new = User.objects.get_or_create(email=row.get('email')) user, new = User.objects.get_or_create(email=row.get('email'))
if new: if new:
self.users.append(user) self.users.append(user)
user.set_encrypted_sensitive_data()
user.save()
self.create_defaults_dids(user)
return user return user
def create_defaults_dids(self, user):
did = DID(label="Default", user=user, type=DID.Types.WEB)
did.set_did()
did.save()
def create_credential(self, user, row): def create_credential(self, user, row):
bcred = VerificableCredential.objects.filter( bcred = VerificableCredential.objects.filter(
user=user, user=user,
@ -382,7 +416,6 @@ class ImportCertificateForm(forms.Form):
return data return data
def new_did(self): def new_did(self):
cert = self.pfx_file
keys = { keys = {
"cert": base64.b64encode(self.pfx_file).decode('utf-8'), "cert": base64.b64encode(self.pfx_file).decode('utf-8'),
"passphrase": self._pss "passphrase": self._pss
@ -397,8 +430,7 @@ class ImportCertificateForm(forms.Form):
type=DID.Types.KEY type=DID.Types.KEY
) )
pw = cache.get("KEY_DIDS") self._did.set_key_material(key_material)
self._did.set_key_material(key_material, pw)
def save(self, commit=True): def save(self, commit=True):

View file

@ -1,9 +1,6 @@
import os import os
import json import json
import logging
import pandas as pd
from pathlib import Path from pathlib import Path
from jsonschema import validate
from smtplib import SMTPException from smtplib import SMTPException
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
@ -18,22 +15,23 @@ 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
from django.core.cache import cache
from utils import credtools from utils import credtools
from idhub_auth.models import User from idhub_auth.models import User
from idhub_auth.forms import ProfileForm from idhub_auth.forms import ProfileForm
from idhub.mixins import AdminView, Http403 from idhub.mixins import AdminView, Http403
from idhub.email.views import NotifyActivateUserByEmail from idhub.email.views import NotifyActivateUserByEmail
from idhub.admin.forms import ( from idhub.admin.forms import (
EncryptionKeyForm,
ImportCertificateForm,
ImportForm, ImportForm,
MembershipForm, MembershipForm,
TermsConditionsForm, TermsConditionsForm,
SchemaForm, SchemaForm,
UserRolForm, UserRolForm
ImportCertificateForm,
) )
from idhub.admin.tables import ( from idhub.admin.tables import (
DashboardTable, DashboardTable,
@ -79,7 +77,27 @@ class TermsAndConditionsView(AdminView, FormView):
return kwargs return kwargs
def form_valid(self, form): def form_valid(self, form):
user = form.save() form.save()
return super().form_valid(form)
class EncryptionKeyView(AdminView, FormView):
template_name = "idhub/admin/encryption_key.html"
title = _('Encryption Key')
section = ""
subtitle = _('Encryption Key')
icon = 'bi bi-key'
form_class = EncryptionKeyForm
success_url = reverse_lazy('idhub:admin_dashboard')
def get(self, request, *args, **kwargs):
if cache.get("KEY_DIDS"):
return redirect(self.success_url)
return super().get(request, *args, **kwargs)
def form_valid(self, form):
form.save()
return super().form_valid(form) return super().form_valid(form)
@ -295,7 +313,11 @@ class PeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
return self.success_url return self.success_url
def form_valid(self, form): def form_valid(self, form):
user = form.save() super().form_valid(form)
user = form.instance
user.set_encrypted_sensitive_data()
user.save()
self.create_defaults_dids(user)
messages.success(self.request, _('The account was created successfully')) messages.success(self.request, _('The account was created successfully'))
Event.set_EV_USR_REGISTERED(user) Event.set_EV_USR_REGISTERED(user)
Event.set_EV_USR_WELCOME(user) Event.set_EV_USR_WELCOME(user)
@ -307,6 +329,11 @@ class PeopleRegisterView(NotifyActivateUserByEmail, People, CreateView):
messages.error(self.request, e) messages.error(self.request, e)
return super().form_valid(form) return super().form_valid(form)
def create_defaults_dids(self, user):
did = DID(label="Default", user=user, type=DID.Types.WEB)
did.set_did()
did.save()
class PeopleMembershipRegisterView(People, FormView): class PeopleMembershipRegisterView(People, FormView):
template_name = "idhub/admin/people_membership_register.html" template_name = "idhub/admin/people_membership_register.html"
@ -679,7 +706,7 @@ class CredentialJsonView(Credentials):
VerificableCredential, VerificableCredential,
pk=pk, pk=pk,
) )
response = HttpResponse(self.object.data, content_type="application/json") response = HttpResponse(self.object.get_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
@ -714,15 +741,10 @@ class DeleteCredentialsView(Credentials):
VerificableCredential, VerificableCredential,
pk=pk, pk=pk,
) )
status = [ self.object.delete()
VerificableCredential.Status.REVOKED, messages.success(self.request, _('Credential deleted successfully'))
VerificableCredential.Status.ISSUED Event.set_EV_CREDENTIAL_DELETED(self.object)
] Event.set_EV_CREDENTIAL_DELETED_BY_ADMIN(self.object)
if self.object.status in status:
self.object.delete()
messages.success(self.request, _('Credential deleted successfully'))
Event.set_EV_CREDENTIAL_DELETED(self.object)
Event.set_EV_CREDENTIAL_DELETED_BY_ADMIN(self.object)
return redirect(self.success_url) return redirect(self.success_url)
@ -760,7 +782,7 @@ 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(cache.get("KEY_DIDS")) form.instance.set_did()
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)
@ -782,7 +804,7 @@ class DidEditView(Credentials, UpdateView):
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
user = form.save() form.save()
messages.success(self.request, _('DID updated successfully')) messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form) return super().form_valid(form)

View file

@ -5,13 +5,12 @@ import json
from pathlib import Path from pathlib import Path
from utils import credtools from utils import credtools
from django.conf import settings from django.conf import settings
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core.cache import cache from django.core.cache import cache
from decouple import config from decouple import config
from idhub.models import DID, Schemas from idhub.models import DID, Schemas
from oidc4vp.models import Organization from oidc4vp.models import Organization
from promotion.models import Promotion
User = get_user_model() User = get_user_model()
@ -23,6 +22,8 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org') ADMIN_EMAIL = config('ADMIN_EMAIL', 'admin@example.org')
ADMIN_PASSWORD = config('ADMIN_PASSWORD', '1234') ADMIN_PASSWORD = config('ADMIN_PASSWORD', '1234')
KEY_DIDS = config('KEY_DIDS')
cache.set("KEY_DIDS", KEY_DIDS, None)
self.create_admin_users(ADMIN_EMAIL, ADMIN_PASSWORD) self.create_admin_users(ADMIN_EMAIL, ADMIN_PASSWORD)
if settings.CREATE_TEST_USERS: if settings.CREATE_TEST_USERS:
@ -43,21 +44,17 @@ class Command(BaseCommand):
def create_admin_users(self, email, password): def create_admin_users(self, email, password):
su = User.objects.create_superuser(email=email, password=password) su = User.objects.create_superuser(email=email, password=password)
su.set_encrypted_sensitive_data(password) su.set_encrypted_sensitive_data()
su.save() su.save()
key = su.decrypt_sensitive_data(password) self.create_defaults_dids(su)
key_dids = {su.id: key}
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):
u = User.objects.create(email=email, password=password) u = User.objects.create(email=email, password=password)
u.set_password(password) u.set_password(password)
u.set_encrypted_sensitive_data(password) u.set_encrypted_sensitive_data()
u.save() u.save()
key = u.decrypt_sensitive_data(password) self.create_defaults_dids(u)
self.create_defaults_dids(u, key)
def create_organizations(self, name, url): def create_organizations(self, name, url):
@ -72,15 +69,14 @@ class Command(BaseCommand):
org1.my_client_secret = org2.client_secret org1.my_client_secret = org2.client_secret
org1.save() org1.save()
org2.save() org2.save()
def create_defaults_dids(self, u, password):
def create_defaults_dids(self, u):
did = DID(label="Default", user=u, type=DID.Types.WEB) did = DID(label="Default", user=u, type=DID.Types.WEB)
did.set_did(password) did.set_did()
did.save() did.save()
def create_schemas(self): def create_schemas(self):
schemas_files = os.listdir(settings.SCHEMAS_DIR) schemas_files = os.listdir(settings.SCHEMAS_DIR)
schemas = [x for x in schemas_files
if not Schemas.objects.filter(file_schema=x).exists()]
for x in schemas_files: for x in schemas_files:
if Schemas.objects.filter(file_schema=x).exists(): if Schemas.objects.filter(file_schema=x).exists():
continue continue

View file

@ -0,0 +1,56 @@
import logging
from urllib.parse import urlparse
from django.conf import settings
from django.template import loader
from django.core.mail import EmailMultiAlternatives
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
logger = logging.getLogger(__name__)
User = get_user_model()
class Command(BaseCommand):
help = "Send mails to the admins for add general key"
subject_template_name = 'idhub/admin/registration/start_app_admin_subject.txt'
email_template_name = 'idhub/admin/registration/start_app_admin_email.txt'
html_email_template_name = 'idhub/admin/registration/start_app_admin_email.html'
def handle(self, *args, **kwargs):
for user in User.objects.filter(is_admin=True):
self.send_email(user)
def send_email(self, user):
"""
Send a email when a user is activated.
"""
parsed_url = urlparse(settings.RESPONSE_URI)
domain = f"{parsed_url.scheme}://{parsed_url.netloc}/"
context = {
"domain": domain,
}
subject = loader.render_to_string(self.subject_template_name, context)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
body = loader.render_to_string(self.email_template_name, context)
from_email = settings.DEFAULT_FROM_EMAIL
to_email = user.email
email_message = EmailMultiAlternatives(
subject, body, from_email, [to_email])
html_email = loader.render_to_string(self.html_email_template_name, context)
email_message.attach_alternative(html_email, 'text/html')
try:
if settings.ENABLE_EMAIL:
email_message.send()
return
logger.warning(to_email)
logger.warning(body)
except Exception as err:
logger.error(err)
return

View file

@ -1,6 +1,5 @@
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.contrib.auth import views as auth_views
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.urls import reverse_lazy, resolve from django.urls import reverse_lazy, resolve
from django.shortcuts import redirect from django.shortcuts import redirect
@ -12,8 +11,8 @@ class Http403(PermissionDenied):
default_detail = _('Permission denied. User is not authenticated') default_detail = _('Permission denied. User is not authenticated')
default_code = 'forbidden' default_code = 'forbidden'
def __init__(self, detail=None, code=None): def __init__(self, details=None, code=None):
if detail is not None: if details is not None:
self.detail = details or self.default_details self.detail = details or self.default_details
if code is not None: if code is not None:
self.code = code or self.default_code self.code = code or self.default_code
@ -22,15 +21,30 @@ class Http403(PermissionDenied):
class UserView(LoginRequiredMixin): class UserView(LoginRequiredMixin):
login_url = "/login/" login_url = "/login/"
wallet = False wallet = False
admin_validated = False
path_terms = [ path_terms = [
'admin_terms_and_conditions', 'admin_terms_and_conditions',
'user_terms_and_conditions', 'user_terms_and_conditions',
'user_gdpr', 'user_gdpr',
'user_waiting',
'user_waiting',
'encryption_key',
] ]
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.admin_validated = cache.get("KEY_DIDS") self.admin_validated = cache.get("KEY_DIDS")
response = super().get(request, *args, **kwargs) response = super().get(request, *args, **kwargs)
if not self.admin_validated:
actual_path = resolve(self.request.path).url_name
if not self.request.user.is_admin:
if actual_path != 'user_waiting':
return redirect(reverse_lazy("idhub:user_waiting"))
if self.request.user.is_admin:
if actual_path != 'encryption_key':
return redirect(reverse_lazy("idhub:encryption_key"))
url = self.check_gdpr() url = self.check_gdpr()
return url or response return url or response

View file

@ -6,10 +6,8 @@ import datetime
from collections import OrderedDict from collections import OrderedDict
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 utils.idhub_ssikit import ( from utils.idhub_ssikit import (
generate_did_controller_key, generate_did_controller_key,
@ -34,26 +32,27 @@ class Event(models.Model):
EV_DID_CREATED = 9, "DID created" EV_DID_CREATED = 9, "DID created"
EV_DID_DELETED = 10, "DID deleted" EV_DID_DELETED = 10, "DID deleted"
EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user" EV_CREDENTIAL_DELETED_BY_USER = 11, "Credential deleted by user"
EV_CREDENTIAL_DELETED = 12, "Credential deleted" EV_CREDENTIAL_DELETED_BY_ADMIN = 12, "Credential deleted by admin"
EV_CREDENTIAL_ISSUED_FOR_USER = 13, "Credential issued for user" EV_CREDENTIAL_DELETED = 13, "Credential deleted"
EV_CREDENTIAL_ISSUED = 14, "Credential issued" EV_CREDENTIAL_ISSUED_FOR_USER = 14, "Credential issued for user"
EV_CREDENTIAL_PRESENTED_BY_USER = 15, "Credential presented by user" EV_CREDENTIAL_ISSUED = 15, "Credential issued"
EV_CREDENTIAL_PRESENTED = 16, "Credential presented" EV_CREDENTIAL_PRESENTED_BY_USER = 16, "Credential presented by user"
EV_CREDENTIAL_ENABLED = 17, "Credential enabled" EV_CREDENTIAL_PRESENTED = 17, "Credential presented"
EV_CREDENTIAL_CAN_BE_REQUESTED = 18, "Credential available" EV_CREDENTIAL_ENABLED = 18, "Credential enabled"
EV_CREDENTIAL_REVOKED_BY_ADMIN = 19, "Credential revoked by admin" EV_CREDENTIAL_CAN_BE_REQUESTED = 19, "Credential available"
EV_CREDENTIAL_REVOKED = 20, "Credential revoked" EV_CREDENTIAL_REVOKED_BY_ADMIN = 20, "Credential revoked by admin"
EV_ROLE_CREATED_BY_ADMIN = 21, "Role created by admin" EV_CREDENTIAL_REVOKED = 21, "Credential revoked"
EV_ROLE_MODIFIED_BY_ADMIN = 22, "Role modified by admin" EV_ROLE_CREATED_BY_ADMIN = 22, "Role created by admin"
EV_ROLE_DELETED_BY_ADMIN = 23, "Role deleted by admin" EV_ROLE_MODIFIED_BY_ADMIN = 23, "Role modified by admin"
EV_SERVICE_CREATED_BY_ADMIN = 24, "Service created by admin" EV_ROLE_DELETED_BY_ADMIN = 24, "Role deleted by admin"
EV_SERVICE_MODIFIED_BY_ADMIN = 25, "Service modified by admin" EV_SERVICE_CREATED_BY_ADMIN = 25, "Service created by admin"
EV_SERVICE_DELETED_BY_ADMIN = 26, "Service deleted by admin" EV_SERVICE_MODIFIED_BY_ADMIN = 26, "Service modified by admin"
EV_ORG_DID_CREATED_BY_ADMIN = 27, "Organisational DID created by admin" EV_SERVICE_DELETED_BY_ADMIN = 27, "Service deleted by admin"
EV_ORG_DID_DELETED_BY_ADMIN = 28, "Organisational DID deleted by admin" EV_ORG_DID_CREATED_BY_ADMIN = 28, "Organisational DID created by admin"
EV_USR_DEACTIVATED_BY_ADMIN = 29, "User deactivated" EV_ORG_DID_DELETED_BY_ADMIN = 29, "Organisational DID deleted by admin"
EV_USR_ACTIVATED_BY_ADMIN = 30, "User activated" EV_USR_DEACTIVATED_BY_ADMIN = 30, "User deactivated"
EV_USR_SEND_VP = 31, "User send Verificable Presentation" EV_USR_ACTIVATED_BY_ADMIN = 31, "User activated"
EV_USR_SEND_VP = 32, "User send Verificable Presentation"
created = models.DateTimeField(_("Date"), auto_now=True) created = models.DateTimeField(_("Date"), auto_now=True)
message = models.CharField(_("Description"), max_length=350) message = models.CharField(_("Description"), max_length=350)
@ -99,9 +98,8 @@ class Event(models.Model):
@classmethod @classmethod
def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user): def set_EV_DATA_UPDATE_REQUESTED_BY_USER(cls, user):
msg = _("The user '{username}' has request the update of the following information: ") msg = _("The user '{username}' has request the update of the following information: ")
msg += "['field1':'value1', 'field2':'value2'>,...]".format( msg += "['field1':'value1', 'field2':'value2'>,...]"
username=user.username, msg = msg.format(username=user.username)
)
cls.objects.create( cls.objects.create(
type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER, type=cls.Types.EV_DATA_UPDATE_REQUESTED_BY_USER,
message=msg, message=msg,
@ -444,11 +442,11 @@ class DID(models.Model):
# JSON-serialized DID document # JSON-serialized DID document
didweb_document = models.TextField() didweb_document = models.TextField()
def get_key_material(self, password): def get_key_material(self):
return self.user.decrypt_data(self.key_material, password) return self.user.decrypt_data(self.key_material)
def set_key_material(self, value, password): def set_key_material(self, value):
self.key_material = self.user.encrypt_data(value, password) self.key_material = self.user.encrypt_data(value)
@property @property
def is_organization_did(self): def is_organization_did(self):
@ -456,9 +454,9 @@ class DID(models.Model):
return True return True
return False return False
def set_did(self, password): def set_did(self):
new_key_material = generate_did_controller_key() new_key_material = generate_did_controller_key()
self.set_key_material(new_key_material, password) self.set_key_material(new_key_material)
if self.type == self.Types.KEY: if self.type == self.Types.KEY:
self.did = keydid_from_controller_key(new_key_material) self.did = keydid_from_controller_key(new_key_material)
@ -621,17 +619,14 @@ class VerificableCredential(models.Model):
return True return True
return False return False
def get_data(self, password): def get_data(self):
if not self.data: if not self.data:
return "" return ""
if self.eidas1_did: return self.user.decrypt_data(self.data)
return self.data
return self.user.decrypt_data(self.data, password)
def set_data(self, value, password): def set_data(self, value):
self.data = self.user.encrypt_data(value, password) self.data = self.user.encrypt_data(value)
def get_description(self): def get_description(self):
return self.schema._description or '' return self.schema._description or ''
@ -649,35 +644,28 @@ class VerificableCredential(models.Model):
return self.Status(self.status).label return self.Status(self.status).label
def get_datas(self): def get_datas(self):
data = json.loads(self.csv_data).items() data = self.render()
return data credential_subject = ujson.loads(data).get("credentialSubject", {})
return credential_subject.items()
def issue(self, did, password, domain=settings.DOMAIN.strip("/")): def issue(self, did, domain=settings.DOMAIN.strip("/")):
if self.status == self.Status.ISSUED: if self.status == self.Status.ISSUED:
return return
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")
# issuer_pass = self.user.decrypt_data(
# cache.get("KEY_DIDS"),
# settings.SECRET_KEY,
# )
# hash of credential without sign # hash of credential without sign
self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest() self.hash = hashlib.sha3_256(self.render(domain).encode()).hexdigest()
data = sign_credential( data = sign_credential(
self.render(domain), self.render(domain),
self.issuer_did.get_key_material(issuer_pass) self.issuer_did.get_key_material()
) )
valid, reason = verify_credential(data) valid, reason = verify_credential(data)
if not valid: if not valid:
return return
if self.eidas1_did: self.data = self.user.encrypt_data(data)
self.data = data
else:
self.data = self.user.encrypt_data(data, password)
self.status = self.Status.ISSUED self.status = self.Status.ISSUED
@ -714,7 +702,7 @@ class VerificableCredential(models.Model):
context.update(d) context.update(d)
return context return context
def render(self, domain): def render(self, domain=""):
context = self.get_context(domain) context = self.get_context(domain)
template_name = 'credentials/{}'.format( template_name = 'credentials/{}'.format(
self.schema.file_schema self.schema.file_schema

View file

@ -46,7 +46,7 @@
class="btn btn-primary form-control" id="submit-id-submit"> class="btn btn-primary form-control" id="submit-id-submit">
</div> </div>
</form> </form>
<div id="login-footer" class="mt-3 d-none"> <div id="login-footer" class="mt-3">
<a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a> <a href="{% url 'idhub:password_reset' %}" data-toggle="modal" data-target="#forgotPasswordModal">{% trans "Forgot your password? Click here to recover" %}</a>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,33 @@
{% extends "idhub/base_admin.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% load django_bootstrap5 %}
<form role="form" method="post">
{% csrf_token %}
{% if form.errors %}
<div class="alert alert-danger alert-icon alert-icon-border alert-dismissible" role="alert">
<div class="icon"><span class="mdi mdi-close-circle-o"></span></div>
<div class="message">
{% for field, error in form.errors.items %}
{{ error }}<br />
{% endfor %}
<button class="btn-close" type="button" data-dismiss="alert" aria-label="Close"></button>
</div>
</div>
{% endif %}
<div class="row">
<div class="col-sm-4">
{% bootstrap_form form %}
</div>
</div>
<div class="form-actions-no-box">
<input class="btn btn-green-admin" type="submit" name="submit" value="{% translate 'Save' %}" />
</div>
</form>
{% endblock %}

View file

@ -12,11 +12,8 @@
<div class="col text-end"> <div class="col text-end">
{% if object.get_status == 'Issued' %} {% if object.get_status == 'Issued' %}
<a class="btn btn-yellow" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-revoke" href="javascript:void()">{% trans 'Revoke' %}</a> <a class="btn btn-yellow" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-revoke" href="javascript:void()">{% trans 'Revoke' %}</a>
<a class="btn btn-orange" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-delete" href="javascript:void()">{% trans 'Delete' %}</a>
{% endif %} {% endif %}
{% if object.get_status == 'Revoked' %}
<a class="btn btn-orange" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-delete" href="javascript:void()">{% trans 'Delete' %}</a> <a class="btn btn-orange" class="btn btn-orange" data-bs-toggle="modal" data-bs-target="#confirm-delete" href="javascript:void()">{% trans 'Delete' %}</a>
{% endif %}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
@ -38,7 +35,7 @@
<strong>{% trans 'Issuance date' %}:</strong> <strong>{% trans 'Issuance date' %}:</strong>
</div> </div>
<div class="col bg-light text-secondary"> <div class="col bg-light text-secondary">
{{ object.issuer_on|default_if_none:"" }} {{ object.issued_on|default_if_none:"" }}
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
@ -49,11 +46,13 @@
{{ object.get_status}} {{ object.get_status}}
</div> </div>
</div> </div>
{% if object.issued_on %}
<div class="row mt-3"> <div class="row mt-3">
<div class="col text-center"> <div class="col text-center">
<a class="btn btn-green-admin" href="{% url 'idhub:admin_credential_json' object.id %}">{% trans 'View in JSON format' %}</a> <a class="btn btn-green-admin" href="{% url 'idhub:admin_credential_json' object.id %}">{% trans 'View in JSON format' %}</a>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
</div> </div>
<!-- Modal Revoke --> <!-- Modal Revoke -->

View file

@ -0,0 +1,9 @@
Hola, se ha reiniciado el servicio de Idhub: {{ domain }}
<br />
no será plenamente funcional hasta que no introduzcas la contraseña de encriptacion del sistema.
<br />
<br />
Por favor entra en la aplicacion como administrador y añade esta contraseña.
<br />
Muchas gracias

View file

@ -0,0 +1,7 @@
Hola, se ha reiniciado el servicio de Idhub: {{ domain }}
no será plenamente funcional hasta que no introduzcas la contraseña de encriptacion del sistema.
Por favor entra en la aplicacion como administrador y añade esta contraseña.
Muchas gracias

View file

@ -0,0 +1 @@
Reinicio de IdHub

View file

@ -25,7 +25,7 @@
<strong>{% trans 'Issuance date' %}:</strong> <strong>{% trans 'Issuance date' %}:</strong>
</div> </div>
<div class="col bg-light text-secondary"> <div class="col bg-light text-secondary">
{{ object.issuer_on|default_if_none:"" }} {{ object.issued_on|default_if_none:"" }}
</div> </div>
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
@ -38,6 +38,7 @@
</div> </div>
</div> </div>
</div> </div>
{% if object.issued_on %}
<div class="row mt-3"> <div class="row mt-3">
{% if object.eidas1_did and admin_validated %} {% if object.eidas1_did and admin_validated %}
<div class="col text-center"> <div class="col text-center">
@ -47,5 +48,6 @@
<div class="col text-center"> <div class="col text-center">
<a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'View credential in JSON format' %}</a> <a class="btn btn-green-user" href="{% url 'idhub:user_credential_json' object.id %}">{% trans 'View credential in JSON format' %}</a>
</div> </div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,10 @@
{% extends "idhub/base.html" %}
{% load i18n %}
{% block content %}
<h3>
<i class="{{ icon }}"></i>
{{ subtitle }}
</h3>
{% trans 'Please contact the administrator to open the service.' %}
{% endblock %}

View file

@ -6,6 +6,7 @@ from unittest.mock import MagicMock
from django.conf import settings from django.conf import settings
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.core.cache import cache
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from idhub_auth.models import User from idhub_auth.models import User
@ -15,6 +16,7 @@ from idhub.models import Event, Membership, Rol, UserRol, Service, Schemas
class AdminDashboardTableTest(TestCase): class AdminDashboardTableTest(TestCase):
def setUp(self): def setUp(self):
cache.set("KEY_DIDS", '1234', None)
self.admin_user = User.objects.create_superuser( self.admin_user = User.objects.create_superuser(
email='adminuser@example.org', email='adminuser@example.org',
password='adminpass12') password='adminpass12')
@ -75,6 +77,7 @@ class AdminDashboardTableTest(TestCase):
class UserTableTest(TestCase): class UserTableTest(TestCase):
def setUp(self): def setUp(self):
cache.set("KEY_DIDS", '1234', None)
self.user1 = User.objects.create(email="user1@example.com") self.user1 = User.objects.create(email="user1@example.com")
self.user2 = User.objects.create(email="user2@example.com") self.user2 = User.objects.create(email="user2@example.com")
Membership.objects.create(user=self.user1, Membership.objects.create(user=self.user1,
@ -106,6 +109,7 @@ class UserTableTest(TestCase):
class TemplateTableTest(TestCase): class TemplateTableTest(TestCase):
def setUp(self): def setUp(self):
cache.set("KEY_DIDS", '1234', None)
self.table = TemplateTable(Schemas.objects.all()) self.table = TemplateTable(Schemas.objects.all())
self.create_schemas(amount=3) self.create_schemas(amount=3)

View file

@ -1,4 +1,5 @@
from django.test import TestCase, RequestFactory from django.test import TestCase, RequestFactory
from django.core.cache import cache
from django.urls import reverse from django.urls import reverse
from idhub_auth.models import User from idhub_auth.models import User
@ -9,6 +10,7 @@ from idhub.admin.views import PeopleListView
class AdminDashboardViewTest(TestCase): class AdminDashboardViewTest(TestCase):
def setUp(self): def setUp(self):
cache.set("KEY_DIDS", '1234', None)
self.user = User.objects.create_user( self.user = User.objects.create_user(
email='normaluser@example.org', email='normaluser@example.org',
password='testpass12', password='testpass12',
@ -99,6 +101,7 @@ class AdminDashboardViewTest(TestCase):
class PeopleListViewTest(TestCase): class PeopleListViewTest(TestCase):
def setUp(self): def setUp(self):
cache.set("KEY_DIDS", '1234', None)
# Set up a RequestFactory to create mock requests # Set up a RequestFactory to create mock requests
self.factory = RequestFactory() self.factory = RequestFactory()
@ -144,6 +147,7 @@ class PeopleListViewTest(TestCase):
class UserDashboardViewTests(TestCase): class UserDashboardViewTests(TestCase):
def setUp(self): def setUp(self):
cache.set("KEY_DIDS", '1234', None)
# Create test users # Create test users
self.admin_user = User.objects.create_superuser('admin@example.org', 'password') self.admin_user = User.objects.create_superuser('admin@example.org', 'password')
self.admin_user.accept_gdpr=True self.admin_user.accept_gdpr=True

View file

@ -88,6 +88,9 @@ urlpatterns = [
path('user/terms/', views_user.TermsAndConditionsView.as_view(), path('user/terms/', views_user.TermsAndConditionsView.as_view(),
name='user_terms_and_conditions'), name='user_terms_and_conditions'),
path('waiting/', views_user.WaitingView.as_view(),
name='user_waiting'),
# Admin # Admin
path('admin/dashboard/', views_admin.DashboardView.as_view(), path('admin/dashboard/', views_admin.DashboardView.as_view(),
name='admin_dashboard'), name='admin_dashboard'),
@ -173,6 +176,7 @@ urlpatterns = [
name='admin_terms_and_conditions'), name='admin_terms_and_conditions'),
path('admin/import/new', views_admin.ImportAddView.as_view(), path('admin/import/new', views_admin.ImportAddView.as_view(),
name='admin_import_add'), name='admin_import_add'),
path('admin/enc/', views_admin.EncryptionKeyView.as_view(), name='encryption_key'),
path('admin/auth/<uuid:admin2fauth>', views_admin.DobleFactorAuthView.as_view(), path('admin/auth/<uuid:admin2fauth>', views_admin.DobleFactorAuthView.as_view(),
name='admin_2fauth'), name='admin_2fauth'),
path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'), path('admin/auth/2f/', DobleFactorSendView.as_view(), name='confirm_send_2f'),

View file

@ -1,3 +1,5 @@
import logging
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -6,6 +8,9 @@ from oidc4vp.models import Organization
from idhub_auth.models import User from idhub_auth.models import User
logger = logging.getLogger(__name__)
class ProfileForm(forms.ModelForm): class ProfileForm(forms.ModelForm):
MANDATORY_FIELDS = ['first_name', 'last_name', 'email'] MANDATORY_FIELDS = ['first_name', 'last_name', 'email']
@ -81,7 +86,6 @@ class RequestCredentialForm(forms.Form):
self.user = kwargs.pop('user', None) self.user = kwargs.pop('user', None)
self.lang = kwargs.pop('lang', None) self.lang = kwargs.pop('lang', None)
self._domain = kwargs.pop('domain', None) self._domain = kwargs.pop('domain', 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)
@ -109,9 +113,9 @@ class RequestCredentialForm(forms.Form):
did = did[0] did = did[0]
cred = cred[0] cred = cred[0]
try: try:
if self.password: cred.issue(did, domain=self._domain)
cred.issue(did, self.password, domain=self._domain) except Exception as err:
except Exception: logger.error(err)
return return
if commit: if commit:

View file

@ -1,8 +1,6 @@
import os
import json import json
import base64 import base64
import qrcode import qrcode
import logging
import datetime import datetime
import weasyprint import weasyprint
import qrcode.image.svg import qrcode.image.svg
@ -23,6 +21,7 @@ from django.views.generic.edit import (
) )
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
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
@ -34,10 +33,7 @@ from idhub.user.tables import (
DIDTable, DIDTable,
CredentialsTable CredentialsTable
) )
from django.core.cache import cache
from django.conf import settings
from idhub.user.forms import ( from idhub.user.forms import (
ProfileForm,
RequestCredentialForm, RequestCredentialForm,
DemandAuthorizationForm, DemandAuthorizationForm,
TermsConditionsForm TermsConditionsForm
@ -176,10 +172,25 @@ class TermsAndConditionsView(UserView, FormView):
return kwargs return kwargs
def form_valid(self, form): def form_valid(self, form):
user = form.save() form.save()
return super().form_valid(form) return super().form_valid(form)
class WaitingView(UserView, TemplateView):
template_name = "idhub/user/waiting.html"
title = _("Comunication with admin")
subtitle = _('Service temporary close')
section = ""
icon = 'bi bi-file-earmark-medical'
success_url = reverse_lazy('idhub:user_dashboard')
def get(self, request, *args, **kwargs):
if cache.get("KEY_DIDS"):
return redirect(self.success_url)
return super().get(request, *args, **kwargs)
class CredentialView(MyWallet, TemplateView): class CredentialView(MyWallet, TemplateView):
template_name = "idhub/user/credential.html" template_name = "idhub/user/credential.html"
subtitle = _('Credential') subtitle = _('Credential')
@ -209,7 +220,8 @@ class CredentialPdfView(MyWallet, TemplateView):
file_name = "certificate.pdf" file_name = "certificate.pdf"
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.admin_validated = cache.get("KEY_DIDS") if not cache.get("KEY_DIDS"):
return redirect(reverse_lazy('idhub:user_dashboard'))
pk = kwargs['pk'] pk = kwargs['pk']
self.user = self.request.user self.user = self.request.user
self.object = get_object_or_404( self.object = get_object_or_404(
@ -235,7 +247,7 @@ class CredentialPdfView(MyWallet, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
this_folder = str(Path.cwd()) # this_folder = str(Path.cwd())
path_img_sig = "idhub/static/images/4_Model_Certificat_html_58d7f7eeb828cf29.jpg" path_img_sig = "idhub/static/images/4_Model_Certificat_html_58d7f7eeb828cf29.jpg"
img_signature = next(Path.cwd().glob(path_img_sig)) img_signature = next(Path.cwd().glob(path_img_sig))
with open(img_signature, 'rb') as _f: with open(img_signature, 'rb') as _f:
@ -297,10 +309,9 @@ class CredentialPdfView(MyWallet, TemplateView):
def get_pfx_data(self): def get_pfx_data(self):
did = self.object.eidas1_did did = self.object.eidas1_did
pw = self.admin_validated if not did:
if not did or not pw:
return None, None return None, None
key_material = json.loads(did.get_key_material(pw)) key_material = json.loads(did.get_key_material())
cert = key_material.get("cert") cert = key_material.get("cert")
passphrase = key_material.get("passphrase") passphrase = key_material.get("passphrase")
if cert and passphrase: if cert and passphrase:
@ -352,14 +363,7 @@ class CredentialJsonView(MyWallet, TemplateView):
pk=pk, pk=pk,
user=self.request.user user=self.request.user
) )
pass_enc = self.request.session.get("key_did") data = self.object.get_data()
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 = 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
@ -374,7 +378,7 @@ class PublicCredentialJsonView(View):
hash=pk, hash=pk,
eidas1_did__isnull=False, eidas1_did__isnull=False,
) )
response = HttpResponse(self.object.data, content_type="application/json") response = HttpResponse(self.object.get_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
@ -388,8 +392,8 @@ class CredentialsRequestView(MyWallet, FormView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs) response = super().get(request, *args, **kwargs)
if not self.admin_validated: if not cache.get("KEY_DIDS"):
return redirect(reverse_lazy('idhub:user_dashboard')) return redirect(reverse_lazy('idhub:user_waiting'))
return response return response
def get_form_kwargs(self): def get_form_kwargs(self):
@ -398,15 +402,6 @@ class CredentialsRequestView(MyWallet, FormView):
kwargs['lang'] = self.request.LANGUAGE_CODE kwargs['lang'] = self.request.LANGUAGE_CODE
domain = "{}://{}".format(self.request.scheme, self.request.get_host()) domain = "{}://{}".format(self.request.scheme, self.request.get_host())
kwargs['domain'] = domain kwargs['domain'] = domain
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):
@ -483,11 +478,7 @@ 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
pw = self.request.user.decrypt_data( form.instance.set_did()
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'))
@ -511,7 +502,7 @@ class DidEditView(MyWallet, UpdateView):
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
user = form.save() form.save()
messages.success(self.request, _('DID updated successfully')) messages.success(self.request, _('DID updated successfully'))
return super().form_valid(form) return super().form_valid(form)

View file

@ -6,7 +6,6 @@ import zlib
import pyroaring import pyroaring
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
@ -18,7 +17,6 @@ from django.http import HttpResponseRedirect, HttpResponse, Http404
from idhub.models import DID, VerificableCredential from idhub.models import DID, VerificableCredential
from idhub.email.views import NotifyActivateUserByEmail from idhub.email.views import NotifyActivateUserByEmail
from trustchain_idhub import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -46,30 +44,20 @@ class LoginView(auth_views.LoginView):
def form_valid(self, form): def form_valid(self, form):
user = form.get_user() user = form.get_user()
password = form.cleaned_data.get("password")
auth_login(self.request, user) auth_login(self.request, user)
sensitive_data_encryption_key = user.decrypt_sensitive_data(password) if user.is_anonymous:
return redirect(reverse_lazy("idhub:login"))
if not user.is_anonymous and user.is_admin: if user.is_admin:
admin_dashboard = reverse_lazy('idhub:admin_dashboard')
self.extra_context['success_url'] = admin_dashboard
# encryption_key = user.encrypt_data(
# sensitive_data_encryption_key,
# settings.SECRET_KEY
# )
# cache.set("KEY_DIDS", encryption_key, None)
cache.set("KEY_DIDS", sensitive_data_encryption_key, None)
if settings.ENABLE_2FACTOR_AUTH: if settings.ENABLE_2FACTOR_AUTH:
self.request.session["2fauth"] = str(uuid.uuid4()) self.request.session["2fauth"] = str(uuid.uuid4())
return redirect(reverse_lazy('idhub:confirm_send_2f')) return redirect(reverse_lazy('idhub:confirm_send_2f'))
self.request.session["key_did"] = user.encrypt_data( admin_dashboard = reverse_lazy('idhub:admin_dashboard')
sensitive_data_encryption_key, self.extra_context['success_url'] = admin_dashboard
user.password+self.request.session._session_key
)
return HttpResponseRedirect(self.extra_context['success_url']) return redirect(self.extra_context['success_url'])
class PasswordResetConfirmView(auth_views.PasswordResetConfirmView): class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
@ -80,7 +68,6 @@ class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
password = form.cleaned_data.get("new_password1") password = form.cleaned_data.get("new_password1")
user = form.user user = form.user
user.set_password(password) user.set_password(password)
user.set_encrypted_sensitive_data(password)
user.save() user.save()
return HttpResponseRedirect(self.success_url) return HttpResponseRedirect(self.success_url)

View file

@ -1,7 +1,7 @@
import nacl import nacl
import base64 import base64
from nacl import pwhash from nacl import pwhash, secret
from django.db import models from django.db import models
from django.core.cache import cache from django.core.cache import cache
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -95,21 +95,24 @@ class User(AbstractBaseUser):
roles.append(r.name) roles.append(r.name)
return ", ".join(set(roles)) return ", ".join(set(roles))
def derive_key_from_password(self, password): def derive_key_from_password(self, password=None):
if not password:
password = cache.get("KEY_DIDS").encode('utf-8')
kdf = pwhash.argon2i.kdf kdf = pwhash.argon2i.kdf
ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE ops = pwhash.argon2i.OPSLIMIT_INTERACTIVE
mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE mem = pwhash.argon2i.MEMLIMIT_INTERACTIVE
return kdf( return kdf(
nacl.secret.SecretBox.KEY_SIZE, secret.SecretBox.KEY_SIZE,
password, password,
self.get_salt(), self.get_salt(),
opslimit=ops, opslimit=ops,
memlimit=mem memlimit=mem
) )
def decrypt_sensitive_data(self, password, data=None): def decrypt_sensitive_data(self, data=None):
sb_key = self.derive_key_from_password(password.encode('utf-8')) sb_key = self.derive_key_from_password()
sb = nacl.secret.SecretBox(sb_key) sb = secret.SecretBox(sb_key)
if not data: if not data:
data = self.get_encrypted_sensitive_data() data = self.get_encrypted_sensitive_data()
if not isinstance(data, bytes): if not isinstance(data, bytes):
@ -117,9 +120,9 @@ class User(AbstractBaseUser):
return sb.decrypt(data).decode('utf-8') return sb.decrypt(data).decode('utf-8')
def encrypt_sensitive_data(self, password, data): def encrypt_sensitive_data(self, data):
sb_key = self.derive_key_from_password(password.encode('utf-8')) sb_key = self.derive_key_from_password()
sb = nacl.secret.SecretBox(sb_key) sb = secret.SecretBox(sb_key)
if not isinstance(data, bytes): if not isinstance(data, bytes):
data = data.encode('utf-8') data = data.encode('utf-8')
@ -134,32 +137,33 @@ class User(AbstractBaseUser):
def get_encrypted_sensitive_data(self): def get_encrypted_sensitive_data(self):
return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8')) return base64.b64decode(self.encrypted_sensitive_data.encode('utf-8'))
def set_encrypted_sensitive_data(self, password): def set_encrypted_sensitive_data(self):
key = base64.b64encode(nacl.utils.random(64)) key = base64.b64encode(nacl.utils.random(64))
self.set_salt() self.set_salt()
key_crypted = self.encrypt_sensitive_data(password, key) key_crypted = self.encrypt_sensitive_data(key)
self.encrypted_sensitive_data = key_crypted self.encrypted_sensitive_data = key_crypted
def encrypt_data(self, data, password): def encrypt_data(self, data):
sb = self.get_secret_box(password) sb = self.get_secret_box()
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, password): def decrypt_data(self, data):
sb = self.get_secret_box(password) sb = self.get_secret_box()
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, password): def get_secret_box(self):
pw = base64.b64decode(password.encode('utf-8')*4) sb_key = self.derive_key_from_password()
sb_key = self.derive_key_from_password(pw) return secret.SecretBox(sb_key)
return nacl.secret.SecretBox(sb_key)
def change_password(self, old_password, new_password): def change_password_key(self, new_password):
sensitive_data = self.decrypt_sensitive_data(old_password) data = self.decrypt_sensitive_data()
self.encrypted_sensitive_data = self.encrypt_sensitive_data( sb_key = self.derive_key_from_password(new_password)
new_password, sb = secret.SecretBox(sb_key)
sensitive_data if not isinstance(data, bytes):
) data = data.encode('utf-8')
self.set_password(new_password)
encrypted_data = base64.b64encode(sb.encrypt(data)).decode('utf-8')
self.encrypted_sensitive_data = encrypted_data

View file

@ -1,14 +1,11 @@
import json import json
import requests
from django import forms from django import forms
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 django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from utils.idhub_ssikit import create_verifiable_presentation from utils.idhub_ssikit import create_verifiable_presentation
from oidc4vp.models import Organization
from idhub.models import VerificableCredential from idhub.models import VerificableCredential
@ -19,7 +16,6 @@ class AuthorizeForm(forms.Form):
self.user = kwargs.pop('user', None) self.user = kwargs.pop('user', None)
self.org = kwargs.pop('org', None) self.org = kwargs.pop('org', None)
self.code = kwargs.pop('code', None) self.code = kwargs.pop('code', None)
self.pw = kwargs.pop('pw', None)
self.presentation_definition = kwargs.pop('presentation_definition', []) self.presentation_definition = kwargs.pop('presentation_definition', [])
self.subject_did = None self.subject_did = None
@ -53,7 +49,6 @@ class AuthorizeForm(forms.Form):
cred = self.user.decrypt_data( cred = self.user.decrypt_data(
c.data, c.data,
self.pw
) )
self.subject_did = c.subject_did self.subject_did = c.subject_did
self.list_credentials.append(cred) self.list_credentials.append(cred)
@ -85,5 +80,5 @@ class AuthorizeForm(forms.Form):
"verifiable_credential_list": vc_list "verifiable_credential_list": vc_list
} }
unsigned_vp = vp_template.render(context) unsigned_vp = vp_template.render(context)
key_material = did.get_key_material(self.pw) key_material = did.get_key_material()
self.vp = create_verifiable_presentation(key_material, unsigned_vp) self.vp = create_verifiable_presentation(key_material, unsigned_vp)

View file

@ -5,7 +5,6 @@ import secrets
from django.conf import settings from django.conf import settings
from django.http import QueryDict from django.http import QueryDict
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.shortcuts import get_object_or_404
from idhub_auth.models import User from idhub_auth.models import User
from django.db import models from django.db import models
from utils.idhub_ssikit import verify_presentation from utils.idhub_ssikit import verify_presentation

View file

@ -16,7 +16,6 @@ from idhub.mixins import UserView
from idhub.models import Event from idhub.models import Event
from oidc4vp.forms import AuthorizeForm from oidc4vp.forms import AuthorizeForm
from utils.idhub_ssikit import verify_presentation
class AuthorizeView(UserView, FormView): class AuthorizeView(UserView, FormView):
@ -39,16 +38,11 @@ class AuthorizeView(UserView, FormView):
kwargs['user'] = self.request.user kwargs['user'] = self.request.user
try: try:
vps = json.loads(self.request.GET.get('presentation_definition')) vps = json.loads(self.request.GET.get('presentation_definition'))
except: except Exception:
vps = [] vps = []
kwargs['presentation_definition'] = vps kwargs['presentation_definition'] = vps
kwargs["org"] = self.get_org() kwargs["org"] = self.get_org()
kwargs["code"] = self.request.GET.get('code') kwargs["code"] = self.request.GET.get('code')
enc_pw = self.request.session["key_did"]
kwargs['pw'] = self.request.user.decrypt_data(
enc_pw,
self.request.user.password+self.request.session._session_key
)
return kwargs return kwargs
def get_form(self, form_class=None): def get_form(self, form_class=None):
@ -64,7 +58,7 @@ class AuthorizeView(UserView, FormView):
return redirect(self.success_url) return redirect(self.success_url)
try: try:
authorization = authorization.json() authorization = authorization.json()
except: except Exception:
messages.error(self.request, _("Error sending credential!")) messages.error(self.request, _("Error sending credential!"))
return redirect(self.success_url) return redirect(self.success_url)
@ -148,7 +142,6 @@ class VerifyView(View):
if len(auth_data) == 2 and auth_data[0].lower() == 'basic': if len(auth_data) == 2 and auth_data[0].lower() == 'basic':
decoded_auth = base64.b64decode(auth_data[1]).decode('utf-8') decoded_auth = base64.b64decode(auth_data[1]).decode('utf-8')
client_id, client_secret = decoded_auth.split(':', 1) client_id, client_secret = decoded_auth.split(':', 1)
org_url = request.GET.get('demand_uri')
org = get_object_or_404( org = get_object_or_404(
Organization, Organization,
client_id=client_id, client_id=client_id,

View file

@ -212,13 +212,11 @@ LOGGING = {
"version": 1, "version": 1,
"disable_existing_loggers": False, "disable_existing_loggers": False,
"handlers": { "handlers": {
"console": {"class": "logging.StreamHandler"}, "console": {"level": "DEBUG", "class": "logging.StreamHandler"},
}, },
"loggers": { "root": {
"django": { "handlers": ["console"],
"handlers": ["console"], "level": "DEBUG",
"level": "INFO",
},
} }
} }