feat: link local library
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import RelyingPartyReport, RelyingPartyTest
|
||||
|
||||
|
||||
@admin.register(RelyingPartyReport)
|
||||
class RelyingPartyReportAdmin(admin.ModelAdmin):
|
||||
search_fields = ("client_id",)
|
||||
list_display = (
|
||||
"client_id", "status", "user", "created", "modified"
|
||||
)
|
||||
list_filter = ("created", "status")
|
||||
|
||||
|
||||
@admin.register(RelyingPartyTest)
|
||||
class RelyingPartyTestAdmin(admin.ModelAdmin):
|
||||
search_fields = ("name", "report__client_id")
|
||||
list_display = (
|
||||
"client_id", "status",
|
||||
"code", "http_status_code", "screenshot_as_html"
|
||||
)
|
||||
list_filter = ("created", "status")
|
||||
readonly_fileds = ("screenshot_as_html",)
|
||||
|
||||
def screenshot_as_html(self, obj):
|
||||
return obj.screenshot # pragma: no cover
|
||||
|
||||
screenshot_as_html.short_description = "Screenshot"
|
||||
@@ -0,0 +1,8 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class RelyingPartyTestConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "spid_cie_oidc.relying_party_test"
|
||||
verbose_name = "SPID/CIE OIDC Federation RP Tests"
|
||||
label = "spid_cie_oidc_relying_party_test"
|
||||
@@ -0,0 +1,28 @@
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class TestingPageAttributesForm(forms.Form):
|
||||
|
||||
attributes = forms.JSONField(
|
||||
initial=dict,
|
||||
label="attributes"
|
||||
)
|
||||
|
||||
|
||||
class TestingPageChecksForm(forms.Form):
|
||||
|
||||
CHOICES = (
|
||||
('send_auth_code_no_code', _('[auth code] send an auth code response without code')),
|
||||
('send_auth_code_no_state', _('[auth code] send an auth code without state')),
|
||||
('unsigned_id_token', _('[token endpoint] release an unsigned id token')),
|
||||
('id_token_with_wrong_signature', _('[token endpoint] release an id token with a wrong signature'))
|
||||
)
|
||||
|
||||
test = forms.ChoiceField(
|
||||
choices=CHOICES,
|
||||
widget=forms.RadioSelect,
|
||||
label="select",
|
||||
# error_messages={"required": _("Select an item")},
|
||||
required=False
|
||||
)
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# Generated by Django 4.0.2 on 2022-03-13 00:41
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import spid_cie_oidc.relying_party_test.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='RelyingPartyReport',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('modified', models.DateTimeField(auto_now=True)),
|
||||
('client_id', models.URLField(blank=True, null=True)),
|
||||
('status', models.CharField(choices=[('unknown', 'Sconosciuto'), ('failed', 'Failed'), ('successfull', 'successfull'), ('error', 'Internal error')], default='unknown', help_text='status', max_length=33)),
|
||||
('report', models.JSONField(blank=True, default=dict, max_length=4096)),
|
||||
('user', models.ForeignKey(blank=True, help_text='Staff user that started the tests', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Relying Party Status',
|
||||
'verbose_name_plural': 'Relying Party Status',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RelyingPartyTest',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('modified', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(max_length=256)),
|
||||
('category', models.CharField(max_length=256)),
|
||||
('code', models.CharField(max_length=256)),
|
||||
('http_status_code', models.PositiveIntegerField()),
|
||||
('screenshot', models.FileField(upload_to=spid_cie_oidc.relying_party_test.models.context_media_path)),
|
||||
('log', models.TextField()),
|
||||
('note', models.TextField()),
|
||||
('status', models.CharField(choices=[('unknown', 'Sconosciuto'), ('failed', 'Failed'), ('successfull', 'successfull'), ('error', 'Internal error')], default='unknown', help_text='status', max_length=33)),
|
||||
('report', models.ForeignKey(help_text='Staff user that started the tests', on_delete=django.db.models.deletion.CASCADE, to='spid_cie_oidc_relying_party_test.relyingpartyreport')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Relying Party Test',
|
||||
'verbose_name_plural': 'Relying Party Tests',
|
||||
},
|
||||
),
|
||||
]
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.0.2 on 2022-03-14 16:40
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('spid_cie_oidc_relying_party_test', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='relyingpartytest',
|
||||
name='report',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spid_cie_oidc_relying_party_test.relyingpartyreport'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,93 @@
|
||||
import logging
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext as _
|
||||
from spid_cie_oidc.entity.abstract_models import TimeStampedModel
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
TEST_STATUS = (
|
||||
("unknown", _("Unknown")),
|
||||
("failed", _("Failed")),
|
||||
("successfull", _("successfull")),
|
||||
("error", _("Internal error"))
|
||||
)
|
||||
|
||||
|
||||
def context_media_path(instance, filename): # pragma: no cover
|
||||
# file will be uploaded to MEDIA_ROOT/...
|
||||
return (
|
||||
f'medias/{instance.client_id}/'
|
||||
f'{instance.report.pk}/'
|
||||
f'{filename}'
|
||||
)
|
||||
|
||||
|
||||
class RelyingPartyReport(TimeStampedModel):
|
||||
"""
|
||||
A test report about a RP
|
||||
"""
|
||||
|
||||
client_id = models.URLField(blank=True, null=True)
|
||||
user = models.ForeignKey(
|
||||
get_user_model(), on_delete=models.SET_NULL,
|
||||
null=True, blank=True,
|
||||
help_text=_("Staff user that started the tests")
|
||||
)
|
||||
status = models.CharField(
|
||||
max_length=33,
|
||||
default = "unknown",
|
||||
help_text=_("status"),
|
||||
choices = TEST_STATUS
|
||||
)
|
||||
|
||||
report = models.JSONField(max_length=4096, blank=True, default=dict)
|
||||
|
||||
def __str__(self):
|
||||
return "{} {}".format(self.client_id, self.status)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Relying Party Status"
|
||||
verbose_name_plural = "Relying Party Status"
|
||||
|
||||
|
||||
class RelyingPartyTest(TimeStampedModel):
|
||||
"""
|
||||
Single tests that belongs to a Report
|
||||
"""
|
||||
|
||||
report = models.ForeignKey(
|
||||
RelyingPartyReport, on_delete=models.CASCADE,
|
||||
help_text=_("")
|
||||
)
|
||||
name = models.CharField(max_length=256)
|
||||
category = models.CharField(max_length=256)
|
||||
code = models.CharField(max_length=256)
|
||||
http_status_code = models.PositiveIntegerField()
|
||||
|
||||
screenshot = models.FileField(
|
||||
upload_to=context_media_path
|
||||
)
|
||||
log = models.TextField()
|
||||
note = models.TextField()
|
||||
|
||||
status = models.CharField(
|
||||
max_length=33,
|
||||
default = "unknown",
|
||||
help_text=_("status"),
|
||||
choices = TEST_STATUS
|
||||
)
|
||||
|
||||
@property
|
||||
def client_id(self):
|
||||
return self.report.client_id
|
||||
|
||||
def __str__(self):
|
||||
return "{} {}".format(self.client_id, self.status)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Relying Party Test"
|
||||
verbose_name_plural = "Relying Party Tests"
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# Pyppeteer
|
||||
|
||||
Note: When you run pyppeteer for the first time, it downloads the latest version of Chromium (~150MB) if it is not found on your system. If you don't prefer this behavior, ensure that a suitable Chrome binary is installed. One way to do this is to run pyppeteer-install command before prior to using this library.
|
||||
|
||||
- Documentation: https://pyppeteer.github.io/pyppeteer/
|
||||
|
||||
## Requisition:
|
||||
|
||||
pyppeteer requires Python >= 3.6
|
||||
|
||||
## Installation:
|
||||
|
||||
Install with pip from PyPI:
|
||||
|
||||
```
|
||||
pip install pyppeteer
|
||||
```
|
||||
|
||||
Or install the latest version from [this github repo](https://github.com/pyppeteer/pyppeteer/):
|
||||
|
||||
```
|
||||
pip install -U git+https://github.com/pyppeteer/pyppeteer@dev
|
||||
```
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import asyncio
|
||||
from pyppeteer import launch
|
||||
import os
|
||||
import json
|
||||
|
||||
BASE_FOLDER = os.path.join(".","spid_cie_oidc","relying_party_test","snippets","results")
|
||||
|
||||
|
||||
class Crawler:
|
||||
|
||||
def __init__(self, url: str, username: str, password: str, testname: str, browser=None):
|
||||
self.url = url
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.testname = testname
|
||||
self.waiting = {"timeout": 60000, "waitUntil": "networkidle0"}
|
||||
if browser:
|
||||
self.browser = browser
|
||||
|
||||
def make_dir_result(self):
|
||||
self.folder = os.path.join(BASE_FOLDER, self.testname)
|
||||
if not os.path.exists(self.folder):
|
||||
os.mkdir(self.folder)
|
||||
|
||||
async def start(self, page= None):
|
||||
self.browser = await launch(headless=False, args= ['--start-maximized'])
|
||||
if page:
|
||||
self.page = page
|
||||
else:
|
||||
self.page = await self.browser.newPage()
|
||||
await self.page.setViewport({"width": 1866, "height": 900})
|
||||
|
||||
page = await self.page.goto(self.url)
|
||||
self.status = page.status
|
||||
|
||||
# async def init_browser(self):
|
||||
# self.browser = await launch(headless=False, args= [ '--start-maximized' ])
|
||||
|
||||
# async def make_page(self,page=None):
|
||||
# if page:
|
||||
# self.page = page
|
||||
# else:
|
||||
# self.page = await self.browser.newPage()
|
||||
# await self.page.setViewport({ "width": 1866, "height": 900})
|
||||
|
||||
# async def goto_url(self):
|
||||
# await self.page.goto(self.url)
|
||||
|
||||
async def goto_login_provider(self):
|
||||
spid_button = await self.page.querySelector(".italia-it-button-icon")
|
||||
await spid_button.click()
|
||||
provider = await self.page.querySelector("#provider-spid")
|
||||
await provider.click()
|
||||
await asyncio.ensure_future(self.page.waitForNavigation(self.waiting))
|
||||
|
||||
async def login(self):
|
||||
lable1 = await self.page.querySelector("#label_username")
|
||||
await lable1.click()
|
||||
await lable1.type(self.username)
|
||||
lable2 = await self.page.querySelector("#label_password")
|
||||
await lable2.click()
|
||||
await lable2.type(self.password)
|
||||
submit = await self.page.querySelector("#submit")
|
||||
await submit.click()
|
||||
page = await asyncio.ensure_future(self.page.waitForNavigation(self.waiting))
|
||||
self.status = page.status
|
||||
|
||||
async def consent(self, selector:str):
|
||||
button = await self.page.querySelector(selector)
|
||||
await button.click()
|
||||
page = await asyncio.ensure_future(self.page.waitForNavigation(self.waiting))
|
||||
self.status = page.status
|
||||
|
||||
async def print_result(self, content, filename, extension):
|
||||
file_name = os.path.join(self.folder, f'{filename}{extension}')
|
||||
f = open(file_name, 'w')
|
||||
f.write(content)
|
||||
f.close()
|
||||
|
||||
async def save_result(self):
|
||||
file_path = os.path.join(self.folder, f'{self.testname}.png')
|
||||
html = await self.page.content()
|
||||
status_code = {"status_code": self.status}
|
||||
await self.print_result(html, self.testname, ".html")
|
||||
await self.print_result(json.dumps(status_code), "status", ".json")
|
||||
await self.page.screenshot({'path': file_path})
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import asyncio
|
||||
from crawler import Crawler
|
||||
|
||||
OIDC_RP_REQUESTS = {
|
||||
"full_authentication_ok": "http://localhost:8000/oidc/rp/landing",
|
||||
}
|
||||
|
||||
|
||||
class Pypper:
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
async def authentication_ok():
|
||||
c = Crawler(OIDC_RP_REQUESTS["full_authentication_ok"],
|
||||
"user",
|
||||
"oidcuser",
|
||||
"authentication_ok"
|
||||
)
|
||||
c.make_dir_result()
|
||||
await c.start()
|
||||
await c.goto_login_provider()
|
||||
await c.login()
|
||||
await c.consent("#agree")
|
||||
await c.save_result()
|
||||
await c.browser.close()
|
||||
|
||||
async def test2():
|
||||
c = Crawler(OIDC_RP_REQUESTS["request_ok"],
|
||||
"user",
|
||||
"oidcuser",
|
||||
"send_request_ok"
|
||||
)
|
||||
c.make_dir_result()
|
||||
await c.start()
|
||||
await c.save_result()
|
||||
await c.browser.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(authentication_ok())
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Vendored
+219
@@ -0,0 +1,219 @@
|
||||
|
||||
{% extends 'op_base.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block menu_links %}
|
||||
|
||||
<li class="nav-item ">
|
||||
<a class="nav-link {% if request.resolver_match.view_name == 'oidc_provider_staff_testing' %}active{% endif %}"
|
||||
href="{% url 'oidc_provider_staff_testing' %}">
|
||||
<span>{% trans 'Home' %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.resolver_match.view_name == 'oidc_provider_access_history' %}active{% endif %}"
|
||||
href="{% url 'oidc_provider_access_history' %}">
|
||||
<span>{% trans 'Access History' %}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{% endblock menu_links %}
|
||||
{% block container %}
|
||||
<div>
|
||||
<div class="container pt-2 p-3">
|
||||
|
||||
|
||||
<div class="d-lg-flex">
|
||||
<div class="col-12">
|
||||
|
||||
<form method="POST" action="{% url 'oidc_provider_staff_testing' %}">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card-space card-wrapper">
|
||||
<div class="card card-bg no-after">
|
||||
<div class="card-body pl-lg-0 pb-0">
|
||||
<div class="h-100">
|
||||
<div class="col-12 pl-lg-4 ">
|
||||
<h4 class="bd-title">{% trans 'Relying Party test page' %}</h4>
|
||||
<p class="mb-0 text-secondary">{% trans "You're a staff user and currently testing " %}<b>{{session.client_id}}</b>.</p>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="card-space card-wrapper">
|
||||
<div class="card card-bg no-after">
|
||||
<div class="card-body p-0">
|
||||
<div class="row h-100">
|
||||
|
||||
|
||||
|
||||
<div class="col-12 col-lg-12">
|
||||
<h5 class="p-2">
|
||||
<svg class="icon icon-secondary icon-sm"><use href="{% static 'svg/sprite.svg' %}#it-settings"></use></svg>
|
||||
Configuration
|
||||
</h5>
|
||||
<div class="p-0">
|
||||
|
||||
<div id="collapseDiv1-sc1" class="collapse-div collapse-background-active" role="tablist">
|
||||
|
||||
<div class="collapse-header" id="heading1-sc1">
|
||||
<div data-toggle="collapse" data-target="#collapse1-sc1" aria-expanded="false"
|
||||
aria-controls="collapse1-sc1">
|
||||
{% trans "Edit redirect uri" %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapse1-sc1" class="collapse" role="tabpanel" aria-labelledby="heading1-sc1">
|
||||
<div class="collapse-body p-2">
|
||||
<p class="p-2 mb-0 text-secondary">{% trans "The callback url where the auth code will be sent" %}</p>
|
||||
<input type="text" value="{{ redirect_uri }}" class="form-control" id="id_redirect_uri">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse-header" id="heading2-sc2">
|
||||
<div data-toggle="collapse" data-target="#collapse2-sc2" aria-expanded="false"
|
||||
aria-controls="collapse1-sc2">
|
||||
{% trans "Edit user attributes" %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapse2-sc2" class="collapse" role="tabpanel" aria-labelledby="heading2-sc2">
|
||||
<div class="collapse-body p-2">
|
||||
|
||||
<textarea rows="10" type="text"
|
||||
class="form-control border" id="id_attributes"
|
||||
name="attributes" >{{attributes}}
|
||||
</textarea>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse-header" id="heading11-sc11">
|
||||
<div data-toggle="collapse" data-target="#collapse11-sc11" aria-expanded="false"
|
||||
aria-controls="collapse11-sc11">
|
||||
{% trans "Edit Authorization url" %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapse11-sc11" class="collapse" role="tabpanel" aria-labelledby="heading11-sc11">
|
||||
<div class="collapse-body p-2">
|
||||
|
||||
<input type="text" value="" placeholder="enter the url to use to batch the tests" class="form-control" id="id_authz_url">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
|
||||
<div class="card-space card-wrapper">
|
||||
<div class="card card-bg no-after h-100">
|
||||
<div class="card-body p-0">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 col-lg-12">
|
||||
<h5 class="p-2">
|
||||
<svg class="icon icon-secondary icon-sm"><use href="{% static 'svg/sprite.svg' %}#it-tool"></use></svg>
|
||||
Tests</h5>
|
||||
<div class="p-0">
|
||||
<div id="collapseDiv11-sc11" class="collapse-div collapse-background-active" role="tablist">
|
||||
|
||||
<div class="collapse-header" id="heading12-sc12">
|
||||
<div data-toggle="collapse" data-target="#collapse12-sc12" aria-expanded="false"
|
||||
aria-controls="collapse12-sc12">
|
||||
|
||||
<span class="badge badge-pill badge-secondary"> </span>
|
||||
<span class="badge badge-pill badge-success">Ok</span>
|
||||
<span class="badge badge-pill badge-danger">Ko</span>
|
||||
|
||||
{% trans "[auth code] send an auth code without state" %}
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapse12-sc12" class="collapse" role="tabpanel" aria-labelledby="heading12-sc12">
|
||||
<div class="collapse-body p-4">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm it-list-wrapper w-25">
|
||||
<ul class="it-list pl-3">
|
||||
<li><b class="text-secondary">{% trans "automatic test" %}</b></li>
|
||||
<li><b>response code</b>: 200</li>
|
||||
<li><b>authz url</b>: url</li>
|
||||
<li><b>redirect uri</b>: url</li>
|
||||
<li><b>last </b>: datetime here</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-sm w-75">
|
||||
<img class="img-fluid" src="{% static 'images/oops.webp' %}" />
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row it-list-wrapper">
|
||||
|
||||
<div class="col-sm-12 text-right">
|
||||
|
||||
<a class="btn btn-primary btn-xs mb-4 mr-4"
|
||||
href="{% url 'oidc_provider_staff_testing' %}">
|
||||
{% trans "Test manually with your browser" %}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-space card-wrapper">
|
||||
<div class="card card-bg no-after">
|
||||
<div class="card-body pl-lg-0 pb-0">
|
||||
<div class="h-100">
|
||||
<div class="col-sm-12 text-center">
|
||||
|
||||
<a href="{% url 'oidc_provider_not_consent' %}?redirect_uri={{ redirect_uri }}"
|
||||
class="italia-it-button italia-it-button-cancel-m button-cancel mb-4 mr-4">
|
||||
<span class="italia-it-buttons-text">{% trans "Deny consent" %}</span>
|
||||
</a>
|
||||
|
||||
<button class="italia-it-button italia-it-button-size-m button-login mb-4 mr-4" type="submit">
|
||||
<span class="italia-it-buttons-text">{% trans "Submit" %}</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock container %}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import Client, TestCase
|
||||
from django.urls import reverse
|
||||
from spid_cie_oidc.authority.tests.settings import rp_conf
|
||||
from spid_cie_oidc.entity.models import FederationEntityConfiguration
|
||||
from spid_cie_oidc.provider.models import OidcSession
|
||||
from spid_cie_oidc.provider.tests.settings import op_conf
|
||||
|
||||
|
||||
class RPTetstTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user = get_user_model().objects.create(
|
||||
username="test",
|
||||
first_name="test",
|
||||
last_name="test",
|
||||
email="[email protected]",
|
||||
is_staff = True
|
||||
)
|
||||
self.user.set_password("test")
|
||||
self.user.save()
|
||||
OidcSession.objects.create(
|
||||
user=self.user,
|
||||
user_uid="",
|
||||
nonce="",
|
||||
authz_request={
|
||||
"scope": "openid",
|
||||
"nonce": "123",
|
||||
"acr_values" : ["https://www.spid.gov.it/SpidL2"],
|
||||
"redirect_uri" : rp_conf["metadata"]["openid_relying_party"]["redirect_uris"][0],
|
||||
"state" : "state",
|
||||
},
|
||||
client_id="",
|
||||
auth_code="code",
|
||||
)
|
||||
self.op_conf = FederationEntityConfiguration.objects.create(**op_conf)
|
||||
|
||||
|
||||
def test_user_staff_get(self):
|
||||
c = Client()
|
||||
c.login(username="test", password="test")
|
||||
session = c.session
|
||||
session.update({"oidc": {"auth_code": "code"}})
|
||||
session.save()
|
||||
url = reverse("oidc_provider_staff_testing")
|
||||
res = c.get(url)
|
||||
self.assertTrue("test page" in res.content.decode())
|
||||
|
||||
def test_user_staff_post(self):
|
||||
c = Client()
|
||||
c.login(username="test", password="test")
|
||||
session = c.session
|
||||
session.update({"oidc": {"auth_code": "code"}})
|
||||
session.save()
|
||||
url = reverse("oidc_provider_staff_testing")
|
||||
res = c.post(url)
|
||||
self.assertTrue(res.status_code == 302)
|
||||
self.assertTrue("callback" in res.url)
|
||||
|
||||
def test_user_staff_get_no_session(self):
|
||||
c = Client()
|
||||
c.login(username="test", password="test")
|
||||
url = reverse("oidc_provider_staff_testing")
|
||||
res = c.get(url)
|
||||
self.assertTrue(res.status_code == 403)
|
||||
|
||||
def test_user_staff_post_no_session(self):
|
||||
c = Client()
|
||||
c.login(username="test", password="test")
|
||||
url = reverse("oidc_provider_staff_testing")
|
||||
res = c.post(url)
|
||||
self.assertTrue(res.status_code == 403)
|
||||
@@ -0,0 +1,18 @@
|
||||
from django.conf import settings
|
||||
from django.urls import path
|
||||
|
||||
from .views import (
|
||||
StaffTestingPageView
|
||||
)
|
||||
|
||||
_PREF = getattr(settings, "OIDC_PREFIX", "oidc/op/rp-test/")
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
path(
|
||||
f"{_PREF}landing/",
|
||||
StaffTestingPageView.as_view(),
|
||||
name="oidc_provider_staff_testing",
|
||||
),
|
||||
|
||||
]
|
||||
@@ -0,0 +1,73 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.views import View
|
||||
from django.shortcuts import render
|
||||
from spid_cie_oidc.provider.models import IssuedToken
|
||||
from spid_cie_oidc.provider.views import OpBase
|
||||
from spid_cie_oidc.relying_party_test.forms import TestingPageAttributesForm, TestingPageChecksForm, _
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StaffTestingPageView(OpBase, View):
|
||||
|
||||
template = "op_user_staff_test.html"
|
||||
|
||||
def get_testing_form(self):
|
||||
return TestingPageChecksForm
|
||||
|
||||
def get(self, request):
|
||||
try:
|
||||
session = self.check_session(request)
|
||||
except Exception:
|
||||
logger.warning("Invalid session")
|
||||
return HttpResponseForbidden()
|
||||
|
||||
session.user
|
||||
attributes = self.attributes_names_to_release(
|
||||
request, session
|
||||
)['filtered_user_claims']
|
||||
|
||||
content = {
|
||||
"form_checks": self.get_testing_form()(),
|
||||
"form_attrs": TestingPageAttributesForm(),
|
||||
"attributes": json.dumps(attributes, indent=4),
|
||||
"session": session,
|
||||
"redirect_uri": session.authz_request.get('redirect_uri', "")
|
||||
}
|
||||
return render(request, self.template, content)
|
||||
|
||||
def post(self, request):
|
||||
|
||||
try:
|
||||
session = self.check_session(request)
|
||||
except Exception:
|
||||
logger.warning("Invalid session")
|
||||
return HttpResponseForbidden()
|
||||
|
||||
form = self.get_testing_form()(request.POST)
|
||||
if not form.is_valid():
|
||||
return self.redirect_response_data(
|
||||
# TODO: this is not normative -> check AgID/IPZS
|
||||
session.authz_request['redirect_uri'],
|
||||
error="rejected_by_user",
|
||||
error_description=_(
|
||||
"User rejected the release of attributes"
|
||||
)
|
||||
)
|
||||
|
||||
issuer = self.get_issuer()
|
||||
iss_token_data = self.get_iss_token_data(session, issuer)
|
||||
|
||||
IssuedToken.objects.create(**iss_token_data)
|
||||
self.payload = session.authz_request
|
||||
|
||||
return self.redirect_response_data(
|
||||
self.payload["redirect_uri"],
|
||||
code=session.auth_code,
|
||||
state=session.authz_request["state"],
|
||||
iss=issuer.sub if issuer else ""
|
||||
)
|
||||
Reference in New Issue
Block a user