From 7db6d1f4e3f73241a0fd008f1352bf2af3b0b06f Mon Sep 17 00:00:00 2001 From: Cayo Puigdefabregas Date: Fri, 24 Nov 2023 16:36:05 +0100 Subject: [PATCH] add oidc4vp module --- idhub/management/commands/initial_datas.py | 2 +- idhub/models.py | 16 ----- idhub/user/forms.py | 5 +- oidc4vp/__init__.py | 0 oidc4vp/admin.py | 3 + oidc4vp/apps.py | 6 ++ oidc4vp/forms.py | 41 ++++++++++++ oidc4vp/migrations/__init__.py | 0 oidc4vp/models.py | 77 ++++++++++++++++++++++ oidc4vp/tests.py | 3 + oidc4vp/views.py | 17 +++++ trustchain_idhub/settings.py | 2 + 12 files changed, 152 insertions(+), 20 deletions(-) create mode 100644 oidc4vp/__init__.py create mode 100644 oidc4vp/admin.py create mode 100644 oidc4vp/apps.py create mode 100644 oidc4vp/forms.py create mode 100644 oidc4vp/migrations/__init__.py create mode 100644 oidc4vp/models.py create mode 100644 oidc4vp/tests.py create mode 100644 oidc4vp/views.py diff --git a/idhub/management/commands/initial_datas.py b/idhub/management/commands/initial_datas.py index acdf6c7..5de2603 100644 --- a/idhub/management/commands/initial_datas.py +++ b/idhub/management/commands/initial_datas.py @@ -5,7 +5,7 @@ from pathlib import Path from django.core.management.base import BaseCommand, CommandError from django.contrib.auth import get_user_model from decouple import config -from idhub.models import Organization +from oidc4vp.models import Organization User = get_user_model() diff --git a/idhub/models.py b/idhub/models.py index 53f8186..09ba43b 100644 --- a/idhub/models.py +++ b/idhub/models.py @@ -1,6 +1,5 @@ import json import pytz -import requests import datetime from django.db import models from django.conf import settings @@ -639,18 +638,3 @@ class UserRol(models.Model): class Meta: unique_together = ('user', 'service',) - - -class Organization(models.Model): - name = models.CharField(max_length=250) - url = models.CharField( - help_text=_("Url where to send the presentation"), - max_length=250 - ) - - def __str__(self): - return self.name - - def send(self, cred): - return - requests.post(self.url, data=cred.data) diff --git a/idhub/user/forms.py b/idhub/user/forms.py index 53a1149..57e3d36 100644 --- a/idhub/user/forms.py +++ b/idhub/user/forms.py @@ -1,7 +1,7 @@ from django import forms from idhub_auth.models import User -from idhub.models import DID, VerificableCredential, Organization - +from idhub.models import DID, VerificableCredential +from oidc4vp.models import Organization class ProfileForm(forms.ModelForm): @@ -56,7 +56,6 @@ class RequestCredentialForm(forms.Form): return - class CredentialPresentationForm(forms.Form): organization = forms.ChoiceField(choices=[]) credential = forms.ChoiceField(choices=[]) diff --git a/oidc4vp/__init__.py b/oidc4vp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oidc4vp/admin.py b/oidc4vp/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/oidc4vp/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/oidc4vp/apps.py b/oidc4vp/apps.py new file mode 100644 index 0000000..1e00f2b --- /dev/null +++ b/oidc4vp/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class Oidc4VpConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'oidc4vp' diff --git a/oidc4vp/forms.py b/oidc4vp/forms.py new file mode 100644 index 0000000..f4f56d5 --- /dev/null +++ b/oidc4vp/forms.py @@ -0,0 +1,41 @@ +from django import forms + + +class Organization(forms.Form): + wallet = forms.ChoiceField( + "Wallet", + choices=[(x.id, x.name) for x in Organization.objects.all()] + ) + + def clean_wallet(self): + data = self.cleaned_data["wallet"] + organization = Organization.objects.filter( + id=data + ) + + if not organization.exists(): + raise ValidationError("organization is not valid!") + + self.organization = organization.first() + + return data + + def authorize(self): + data = { + "response_type": "vp_token", + "response_mode": "direct_post", + "client_id": self.organization.client_id, + "response_uri": settings.RESPONSE_URI, + "presentation_definition": self.pv_definition(), + "nonce": "" + } + query_dict = QueryDict('', mutable=True) + query_dict.update(data) + + url = '{response_uri}/authorize?{params}'.format( + response_uri=self.organization.response_uri, + params=query_dict.urlencode() + ) + + def pv_definition(self): + return "" diff --git a/oidc4vp/migrations/__init__.py b/oidc4vp/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oidc4vp/models.py b/oidc4vp/models.py new file mode 100644 index 0000000..ac6da6d --- /dev/null +++ b/oidc4vp/models.py @@ -0,0 +1,77 @@ +import requests + +from django.db import models +from django.http import QueryDict +from django.utils.translation import gettext_lazy as _ +from idhub_auth.models import User + + +class Organization(models.Model): + name = models.CharField(max_length=250) + client_id = models.CharField() + client_secret = models.CharField() + response_uri = models.URLField( + help_text=_("Url where to send the presentation"), + max_length=250 + ) + + def __str__(self): + return self.name + + def send(self, vcred): + return requests.post(self.url, data=vcred) + + +class Authorization(models.Model): + created = models.DateTimeField(auto_now=True) + presentation_definition = models.CharField() + organization = models.ForeignKey( + Organization, + on_delete=models.CASCADE, + related_name='vp_tokens', + null=True, + ) + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + null=True, + ) + + def authorize(self): + response_uri = self.__class__.objects.filter( + response_uri=settings.RESPONSE_URI + ) + data = { + "response_type": "vp_token", + "response_mode": "direct_post", + "client_id": "...", + "response_uri": response_uri, + "presentation_definition": "...", + "nonce": "" + } + query_dict = QueryDict('', mutable=True) + query_dict.update(data) + + url = '{response_uri}/authorize?{params}'.format( + response_uri=self.organization.response_uri, + params=query_dict.urlencode() + ) + +class OAuth2VPToken(models.Model): + created = models.DateTimeField(auto_now=True) + response_code = models.CharField() + result_verify = models.BooleanField() + presentation_definition = models.CharField() + organization = models.ForeignKey( + Organization, + on_delete=models.CASCADE, + related_name='vp_tokens', + null=True, + ) + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + related_name='vp_tokens', + null=True, + ) + diff --git a/oidc4vp/tests.py b/oidc4vp/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/oidc4vp/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/oidc4vp/views.py b/oidc4vp/views.py new file mode 100644 index 0000000..42e1a58 --- /dev/null +++ b/oidc4vp/views.py @@ -0,0 +1,17 @@ +from django.shortcuts import render + +class PeopleEditView(People, FormView): + template_name = "idhub/admin/user_edit.html" + form_class = ProfileForm + success_url = reverse_lazy('idhub:admin_people_list') + + + def form_valid(self, form): + user = form.save() + messages.success(self.request, _('The credential was sended successfully')) + # Event.set_EV_USR_UPDATED_BY_ADMIN(user) + # Event.set_EV_USR_UPDATED(user) + + return super().form_valid(form) + + diff --git a/trustchain_idhub/settings.py b/trustchain_idhub/settings.py index 30bbc0a..df36198 100644 --- a/trustchain_idhub/settings.py +++ b/trustchain_idhub/settings.py @@ -71,6 +71,7 @@ INSTALLED_APPS = [ 'django_extensions', 'django_bootstrap5', 'idhub_auth', + 'oidc4vp', 'idhub' ] @@ -183,3 +184,4 @@ USE_I18N = True USE_L10N = True AUTH_USER_MODEL = 'idhub_auth.User' +RESPONSE_URI = config('RESPONSE_URI', default="")