demand authorization

This commit is contained in:
Cayo Puigdefabregas 2023-11-28 09:39:02 +01:00
parent d57b3fc02c
commit 19e44cf52d
11 changed files with 171 additions and 57 deletions

View File

@ -1,2 +1,4 @@
"ExO";"https://verify.exo.cat" "ExO";"https://verify.exo.cat"
"Somos Connexión";"https://verify.somosconexion.coop" "Somos Connexión";"https://verify.somosconexion.coop"
"test2";"http://localhost:9000/verify"
"test1";"http://localhost:8000/verify"

1 ExO https://verify.exo.cat
2 Somos Connexión https://verify.somosconexion.coop
3 test2 http://localhost:9000/verify
4 test1 http://localhost:8000/verify

View File

@ -41,4 +41,4 @@ class Command(BaseCommand):
def create_organizations(self, name, url): def create_organizations(self, name, url):
Organization.objects.create(name=name, url=url) Organization.objects.create(name=name, response_uri=url)

View File

@ -115,7 +115,7 @@
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link {% if path == 'user_credentials_presentation' %}active2{% endif %}" href="{% url 'idhub:user_credentials_presentation' %}"> <a class="nav-link {% if path == 'user_demand_authorization' %}active2{% endif %}" href="{% url 'idhub:user_demand_authorization' %}">
{% trans 'Present a credential' %} {% trans 'Present a credential' %}
</a> </a>
</li> </li>

View File

@ -20,7 +20,7 @@ from django.urls import path, reverse_lazy
from .views import LoginView from .views import LoginView
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
from .verification_portal import views as views_verification_portal # from .verification_portal import views as views_verification_portal
app_name = 'idhub' app_name = 'idhub'
@ -85,6 +85,9 @@ urlpatterns = [
path('user/credentials/request/', path('user/credentials/request/',
views_user.CredentialsRequestView.as_view(), views_user.CredentialsRequestView.as_view(),
name='user_credentials_request'), name='user_credentials_request'),
path('user/credentials_presentation/demand',
views_user.DemandAuthorizationView.as_view(),
name='user_demand_authorization'),
path('user/credentials_presentation/', path('user/credentials_presentation/',
views_user.CredentialsPresentationView.as_view(), views_user.CredentialsPresentationView.as_view(),
name='user_credentials_presentation'), name='user_credentials_presentation'),
@ -173,6 +176,6 @@ urlpatterns = [
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('verification_portal/verify/', views_verification_portal.verify, # path('verification_portal/verify/', views_verification_portal.verify,
name="verification_portal_verify") # name="verification_portal_verify")
] ]

View File

@ -1,4 +1,6 @@
import requests
from django import forms from django import forms
from django.conf import settings
from idhub_auth.models import User from idhub_auth.models import User
from idhub.models import DID, VerificableCredential from idhub.models import DID, VerificableCredential
from oidc4vp.models import Organization from oidc4vp.models import Organization
@ -56,9 +58,40 @@ class RequestCredentialForm(forms.Form):
return return
class DemandAuthorizationForm(forms.Form):
organization = forms.ChoiceField(choices=[])
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
self.fields['organization'].choices = [
(x.id, x.name) for x in Organization.objects.filter()
if x.response_uri != settings.RESPONSE_URI
]
def save(self, commit=True):
self.org = Organization.objects.filter(
id=self.data['organization']
)
if not self.org.exists():
return
self.org = self.org[0]
if commit:
url = self.org.demand_authorization()
auth = (self.org.client_id, self.org.client_secret)
# res = requests.get(url, auth=auth)
# import pdb; pdb.set_trace()
# if res.status == 200:
# return res.body
return
class CredentialPresentationForm(forms.Form): class CredentialPresentationForm(forms.Form):
organization = forms.ChoiceField(choices=[]) organization = forms.ChoiceField(choices=[])
credential = forms.ChoiceField(choices=[]) # credential = forms.ChoiceField(choices=[])
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None) self.user = kwargs.pop('user', None)
@ -66,12 +99,12 @@ class CredentialPresentationForm(forms.Form):
self.fields['organization'].choices = [ self.fields['organization'].choices = [
(x.id, x.name) for x in Organization.objects.filter() (x.id, x.name) for x in Organization.objects.filter()
] ]
self.fields['credential'].choices = [ # self.fields['credential'].choices = [
(x.id, x.type()) for x in VerificableCredential.objects.filter( # (x.id, x.type()) for x in VerificableCredential.objects.filter(
user=self.user, # user=self.user,
status=VerificableCredential.Status.ISSUED # status=VerificableCredential.Status.ISSUED
) # )
] # ]
def save(self, commit=True): def save(self, commit=True):
self.org = Organization.objects.filter( self.org = Organization.objects.filter(

View File

@ -12,7 +12,12 @@ from django.shortcuts import get_object_or_404, redirect
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 idhub.user.forms import ProfileForm, RequestCredentialForm, CredentialPresentationForm from idhub.user.forms import (
ProfileForm,
RequestCredentialForm,
CredentialPresentationForm,
DemandAuthorizationForm
)
from idhub.mixins import UserView from idhub.mixins import UserView
from idhub.models import DID, VerificableCredential, Event from idhub.models import DID, VerificableCredential, Event
@ -141,6 +146,28 @@ class CredentialsRequestView(MyWallet, FormView):
return super().form_valid(form) return super().form_valid(form)
class DemandAuthorizationView(MyWallet, FormView):
template_name = "idhub/user/credentials_presentation.html"
subtitle = _('Credential presentation')
icon = 'bi bi-patch-check-fill'
form_class = DemandAuthorizationForm
success_url = reverse_lazy('idhub:user_demand_authorization')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
authorization = form.save()
if authorization:
if authorization.get('redirect_uri'):
redirect(authorization.get('redirect_uri'))
else:
messages.error(self.request, _("Error sending credential!"))
return super().form_valid(form)
class CredentialsPresentationView(MyWallet, FormView): class CredentialsPresentationView(MyWallet, FormView):
template_name = "idhub/user/credentials_presentation.html" template_name = "idhub/user/credentials_presentation.html"
subtitle = _('Credential presentation') subtitle = _('Credential presentation')
@ -151,6 +178,7 @@ class CredentialsPresentationView(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
kwargs['authorize'] = self.request.GET.params.get("uri")
return kwargs return kwargs
def form_valid(self, form): def form_valid(self, form):

View File

@ -54,12 +54,27 @@ class Organization(models.Model):
""" """
Send the verificable presentation to Verifier Send the verificable presentation to Verifier
""" """
org = Organization.objects.get( org = self.__class__.objects.get(
response_uri=settings.RESPONSE_URI response_uri=settings.RESPONSE_URI
) )
auth = (org.client_id, org.client_secret) auth = (org.client_id, org.client_secret)
return requests.post(self.url, data=vp, auth=auth) return requests.post(self.url, data=vp, auth=auth)
def demand_authorization(self):
"""
Send the a request for start a process of Verifier
"""
org = self.__class__.objects.get(
response_uri=settings.RESPONSE_URI
)
# import pdb; pdb.set_trace()
url = "{url}/?demand_uri={redirect_uri}".format(
url=self.response_uri.strip("/"),
redirect_uri=settings.RESPONSE_URI
)
auth = (org.client_id, org.client_secret)
return requests.get(url, auth=auth)
def __str__(self): def __str__(self):
return self.name return self.name
@ -75,11 +90,11 @@ class Authorization(models.Model):
The Verifier need to do a redirection to the user to Wallet. The Verifier need to do a redirection to the user to Wallet.
The code we use as a soft foreing key between Authorization and OAuth2VPToken. The code we use as a soft foreing key between Authorization and OAuth2VPToken.
""" """
nonce = models.CharField(max_length=50) # nonce = models.CharField(max_length=50)
expected_credentials = models.CharField(max_length=255) # expected_credentials = models.CharField(max_length=255)
expected_contents = models.TextField() # expected_contents = models.TextField()
action = models.TextField() # action = models.TextField()
response_or_redirect = models.CharField(max_length=255) # response_or_redirect = models.CharField(max_length=255)
code = models.CharField(max_length=24, default=set_code) code = models.CharField(max_length=24, default=set_code)
created = models.DateTimeField(auto_now=True) created = models.DateTimeField(auto_now=True)
@ -98,7 +113,7 @@ class Authorization(models.Model):
def authorize(self): def authorize(self):
response_uri = self.__class__.objects.filter( response_uri = self.__class__.objects.filter(
response_uri=settings.RESPONSE_URI response_uri=settings.ALLOW_CODE_URI
) )
data = { data = {
"response_type": "vp_token", "response_type": "vp_token",

View File

@ -6,44 +6,75 @@ from django.http import HttpResponse, HttpResponseRedirect
from utils.idhub_ssikit import verify_presentation from utils.idhub_ssikit import verify_presentation
from .models import VPVerifyRequest from .models import VPVerifyRequest
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from more_itertools import flatten, unique_everseen # from more_itertools import flatten, unique_everseen
from oidc4vp.models import Authorization
# class PeopleListView(People, TemplateView):
# template_name = "idhub/admin/people.html"
# subtitle = _('View users')
# icon = 'bi bi-person'
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context.update({
# 'users': User.objects.filter(),
# })
# return context
def DemandAuthorizationView(request):
assert request.method == "GET"
import pdb; pdb.set_trace()
params = request.GET.params
org = Organization.objects.filter(
url=params.get('redirect_uri')
)
authorization = Authorization(
organization=org,
presentation_definition="MemberCredential"
)
# authorization.save()
res = json.dumps({"uri": authorization.authorize()})
return HttpResponse(res)
def verify(request): def verify(request):
assert request.method == "POST" import pdb; pdb.set_trace()
# TODO: incorporate request.POST["presentation_submission"] as schema definition # assert request.method == "POST"
(presentation_valid, _) = verify_presentation(request.POST["vp_token"]) # # TODO: incorporate request.POST["presentation_submission"] as schema definition
if not presentation_valid: # (presentation_valid, _) = verify_presentation(request.POST["vp_token"])
raise Exception("Failed to verify signature on the given Verifiable Presentation.") # if not presentation_valid:
vp = json.loads(request.POST["vp_token"]) # raise Exception("Failed to verify signature on the given Verifiable Presentation.")
nonce = vp["nonce"] # vp = json.loads(request.POST["vp_token"])
# "vr" = verification_request # nonce = vp["nonce"]
vr = get_object_or_404(VPVerifyRequest, nonce=nonce) # TODO: return meaningful error, not 404 # # "vr" = verification_request
# Get a list of all included verifiable credential types # vr = get_object_or_404(VPVerifyRequest, nonce=nonce) # TODO: return meaningful error, not 404
included_credential_types = unique_everseen(flatten([ # # Get a list of all included verifiable credential types
vc["type"] for vc in vp["verifiableCredential"] # included_credential_types = unique_everseen(flatten([
])) # vc["type"] for vc in vp["verifiableCredential"]
# Check that it matches what we requested # ]))
for requested_vc_type in json.loads(vr.expected_credentials): # # Check that it matches what we requested
if requested_vc_type not in included_credential_types: # for requested_vc_type in json.loads(vr.expected_credentials):
raise Exception("You're missing some credentials we requested!") # TODO: return meaningful error # if requested_vc_type not in included_credential_types:
# Perform whatever action we have to do # raise Exception("You're missing some credentials we requested!") # TODO: return meaningful error
action = json.loads(vr.action) # # Perform whatever action we have to do
if action["action"] == "send_mail": # action = json.loads(vr.action)
subject = action["params"]["subject"] # if action["action"] == "send_mail":
to_email = action["params"]["to"] # subject = action["params"]["subject"]
from_email = "noreply@verifier-portal" # to_email = action["params"]["to"]
body = request.POST["vp-token"] # from_email = "noreply@verifier-portal"
send_mail( # body = request.POST["vp-token"]
subject, # send_mail(
body, # subject,
from_email, # body,
[to_email] # from_email,
) # [to_email]
elif action["action"] == "something-else": # )
pass # elif action["action"] == "something-else":
else: # pass
raise Exception("Unknown action!") # else:
# OK! Your verifiable presentation was successfully presented. # raise Exception("Unknown action!")
return HttpResponseRedirect(vr.response_or_redirect) # # OK! Your verifiable presentation was successfully presented.
# return HttpResponseRedirect(vr.response_or_redirect)

View File

@ -186,3 +186,4 @@ USE_L10N = True
AUTH_USER_MODEL = 'idhub_auth.User' AUTH_USER_MODEL = 'idhub_auth.User'
RESPONSE_URI = config('RESPONSE_URI', default="") RESPONSE_URI = config('RESPONSE_URI', default="")
ALLOW_CODE_URI= config('ALLOW_CODE_URI', default="")

View File

@ -24,4 +24,5 @@ from django.contrib.auth import views as auth_views
urlpatterns = [ urlpatterns = [
# path('django-admin/', admin.site.urls), # path('django-admin/', admin.site.urls),
path('', include('idhub.urls')), path('', include('idhub.urls')),
path('oidc4vp/', include('oidc4vp.urls')),
] ]