demand authorization
This commit is contained in:
parent
d57b3fc02c
commit
19e44cf52d
|
@ -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"
|
||||||
|
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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")
|
||||||
]
|
]
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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",
|
||||||
|
|
105
oidc4vp/views.py
105
oidc4vp/views.py
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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="")
|
||||||
|
|
|
@ -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')),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue