Pdnd.Metadata.AspNetCore
1.0.0
dotnet add package Pdnd.Metadata.AspNetCore --version 1.0.0
NuGet\Install-Package Pdnd.Metadata.AspNetCore -Version 1.0.0
<PackageReference Include="Pdnd.Metadata.AspNetCore" Version="1.0.0" />
<PackageVersion Include="Pdnd.Metadata.AspNetCore" Version="1.0.0" />
<PackageReference Include="Pdnd.Metadata.AspNetCore" />
paket add Pdnd.Metadata.AspNetCore --version 1.0.0
#r "nuget: Pdnd.Metadata.AspNetCore, 1.0.0"
#:package Pdnd.Metadata.AspNetCore@1.0.0
#addin nuget:?package=Pdnd.Metadata.AspNetCore&version=1.0.0
#tool nuget:?package=Pdnd.Metadata.AspNetCore&version=1.0.0
Pdnd.Metadata
Pdnd.Metadata è una libreria .NET leggera pensata per estrarre in modo strutturato i metadati delle richieste HTTP in ingresso, in un formato indipendente dal framework web, con supporto dedicato per scenari PDND (voucher, tracking evidence, digest, DPoP) e per i segnali standard di correlazione e tracing.
La libreria nasce da un’esigenza molto pratica: quando esponi un e-service come provider (erogatore), devi spesso capire chi sta chiamando, con quale contesto PDND, e come la chiamata può essere correlata e auditata, senza disseminare parsing “ad hoc” degli header tra controller, minimal API e middleware.
Contenuti
| Sezione | Cosa troverai |
|---|---|
| Perché esiste questa libreria | Il problema che risolve nei servizi provider reali |
| Panoramica PDND | Cos’è la PDND e perché la richiesta in ingresso trasporta token |
| Cosa fa Pdnd.Metadata | Responsabilità, modello dati e confini |
| Campi estratti | Chiavi canoniche prodotte dall’estrattore (generiche + specifiche PDND) |
| Modello di sicurezza | Cosa non viene mai memorizzato, comportamento fail-soft, default consigliati |
| Struttura dei pacchetti | Core vs integrazione ASP.NET Core |
| Quick start (ASP.NET Core) | Registrazione, middleware e consumo dei metadati |
| Configurazione consigliata per produzione | Postura conservativa e note di governance |
| API di esempio | Endpoint per verificare localmente l’estrazione |
| Cosa questa libreria non fa | Non-obiettivi espliciti (validazione, enforcement, chiamate API PDND) |
| Schema chiavi canoniche | Riferimento completo di tutte le chiavi di metadati estratte |
| Riferimenti ufficiali PDND | Link alla documentazione ufficiale |
| Autore e maintainer | Proprietà e manutenzione del progetto |
| Contribuire | Come contribuire al progetto |
| Licenza | Informazioni sulla licenza |
| Contatti | Informazioni di contatto |
Perché esiste questa libreria
Nei servizi provider, l’estrazione dei metadati tende a crescere in modo organico:
- team diversi parsano header diversi in modo diverso,
- gli ID di correlazione vengono duplicati o sovrascritti,
- i token PDND vengono trattati come stringhe raw (con rischio di log accidentali),
- e la stessa logica viene reimplementata in controller, minimal API o filtri di gateway.
Pdnd.Metadata standardizza questo lavoro:
- raccoglie i metadati in uno snapshot strutturato (
PdndCallerMetadata), - estrae le informazioni PDND in modalità best-effort e non bloccante,
- applica “safe defaults” (niente
Authorizationraw, niente blob firmati salvati di default), - mantiene separata l’integrazione ASP.NET Core dalla logica core di estrazione.
Panoramica PDND
PDND abilita lo scambio sicuro e tracciabile di servizi e dati tra amministrazioni. Nel pattern di interazione più comune, il fruitore chiama l’erogatore inviando un voucher (JWT) in:
Authorization: Bearer <voucher>
Riferimento ufficiale: utilizzo voucher. (developer.pagopa.it)
Per alcuni e-service, informazioni aggiuntive vengono veicolate tramite un token di Tracking Evidence in un header dedicato. Riferimento ufficiale: “voucher bearer … con informazioni aggiuntive”. (developer.pagopa.it)
La libreria cattura anche segnali standard di correlazione e tracing comunemente usati nei moderni servizi HTTP (es. W3C Trace Context). PDND fornisce indicazioni su pratiche di tracing e osservabilità per il monitoraggio dell’interoperabilità. Riferimento ufficiale: manuale tracing. (developer.pagopa.it)
Infine, la piattaforma include flussi DPoP (proof-of-possession). Riferimento ufficiale: approfondimento su DPoP. (developer.pagopa.it)
Cosa fa Pdnd.Metadata
A runtime, la libreria costruisce uno snapshot di metadati che rappresenta ciò che è possibile inferire in modo sicuro e utile dalla richiesta in ingresso:
Metadati generici della richiesta
- method/scheme/host/path/query
- IP e porte remote/local
- catena forwarded normalizzata (best-effort)
- hint di correlazione e tracing (W3C trace context + request id comuni)
- header selezionati (regole di cattura configurabili)
Estrazione PDND-aware (best-effort)
- voucher: parsing del JOSE header JWT (alg/kid/typ) e payload, estrazione di claim standard e PDND-specific
- tracking evidence: parsing di header/payload token ed estrazione di campi selezionati
- digest: parsing del valore dell'header
Digestin una coppia normalizzata (alg, value) - content-digest: parsing dell'header
Content-Digest(RFC 9530) in una coppia normalizzata (alg, value) - DPoP: parsing di header/payload proof token ed estrazione di campi selezionati (incl. ath, nonce per RFC 9449)
- signature: parsing dell'header
Agid-JWT-Signatureper campi di integrità della richiesta
Comportamento fail-soft
- header mancanti ignorati
- errori di parsing ignorati
- token troppo grandi saltati (guard-rail tramite
MaxTokenLength)
L’output è pensato per essere stabile e facile da integrare con sistemi di logging, auditing o dashboard di tracing interne, senza esporre segreti.
Campi estratti
Lo snapshot è un PdndCallerMetadata contenente item indicizzati da chiavi canoniche.
Chiavi generiche
http.method,http.scheme,http.host,http.path,http.querynet.remote_ip,net.remote_port,net.local_ip,net.local_port,net.forwarded_forcorrelation.idtrace.traceparent,trace.tracestate,trace.baggagehttp.header.<lowercase-name>(solo se l’header capture è abilitato e l’header non è negato)
Nota sugli header forwarded: valori come
Forwarded/X-Forwarded-Forsono affidabili solo se impostati da un reverse proxy o API gateway trusted. In reti aperte sono controllabili dall’utente e non vanno considerati segnali di identità autorevoli.
Chiavi PDND
Voucher (da Authorization: Bearer ...)
pdnd.voucher.alg,pdnd.voucher.kid,pdnd.voucher.typ(JOSE header)pdnd.voucher.isspdnd.voucher.subpdnd.voucher.aud(stringa normalizzata; può originare da un array JWT)pdnd.voucher.jtipdnd.voucher.iat,pdnd.voucher.nbf,pdnd.voucher.exp(memorizzati come stringhe; tipicamente epoch seconds)pdnd.voucher.purposeId(se presente)pdnd.voucher.clientId,pdnd.voucher.client_id(se presente)pdnd.voucher.organizationId(organizzazione fruitore PDND, se presente)pdnd.voucher.dnonce(nonce anti-replay, se presente)
Riferimento: utilizzo e semantica voucher. (developer.pagopa.it)
Tracking Evidence (da Agid-JWT-Tracking-Evidence / AgID-JWT-TrackingEvidence)
pdnd.trackingEvidence.alg,pdnd.trackingEvidence.kid,pdnd.trackingEvidence.typpdnd.trackingEvidence.iss,pdnd.trackingEvidence.sub,pdnd.trackingEvidence.jti(se presenti)pdnd.trackingEvidence.aud(se presente; puo essere separato da virgole)pdnd.trackingEvidence.iat,pdnd.trackingEvidence.nbf,pdnd.trackingEvidence.exp(se presenti)
Nota di compatibilità: nella documentazione PDND il nome dell’header appare in due varianti (Agid-JWT-Tracking-Evidence e AgID-JWT-TrackingEvidence). L’estrattore supporta entrambe per interoperabilità.
Riferimento: flussi con informazioni aggiuntive. (developer.pagopa.it)
Digest (da Digest)
pdnd.digest.algpdnd.digest.value
Riferimento: note digest nelle FAQ voucher. (developer.pagopa.it)
DPoP (da DPoP)
pdnd.dpop.alg,pdnd.dpop.kid,pdnd.dpop.typpdnd.dpop.htm,pdnd.dpop.htu,pdnd.dpop.jti,pdnd.dpop.iat,pdnd.dpop.exp(se presenti)pdnd.dpop.ath(hash access token, RFC 9449 u00a74.2)pdnd.dpop.nonce(nonce fornito dal server, RFC 9449 u00a74.3)
Riferimento: approfondimento DPoP. (developer.pagopa.it)
Content-Digest (da Content-Digest, RFC 9530)
pdnd.content_digest.algpdnd.content_digest.value
RFC 9530 sostituisce l'header legacy Digest con Content-Digest usando il formato structured field dictionary (alg=:base64value:). La libreria supporta entrambi.
Agid-JWT-Signature (da Agid-JWT-Signature)
pdnd.signature.alg,pdnd.signature.kid,pdnd.signature.typ(JOSE header)pdnd.signature.iss,pdnd.signature.sub,pdnd.signature.jti(se presenti)pdnd.signature.aud(se presente; puo essere separato da virgole)pdnd.signature.iat,pdnd.signature.exp(se presenti)pdnd.signature.signed_headers(digest degli header firmati per integrita)
Usato nel pattern PDND INTEGRITY_REST_01 per la firma delle richieste.
Modello di sicurezza
Cosa non viene mai memorizzato (raw)
Di default, la libreria non memorizza mai:
Authorization(raw)Cookie,Set-Cookie
Questo previene la persistenza o il logging accidentale di segreti.
Blob firmati (raw)
Di default, la libreria non memorizza valori raw per:
- header Tracking Evidence
- header DPoP
- header Agid-JWT-Signature
Invece, effettua parsing best-effort e memorizza campi selezionati sotto chiavi canoniche pdnd.*. Questo rende l’output ispezionabile riducendo il rischio di leakage.
Comportamento fail-soft
- Qualunque errore di parsing viene ignorato; la request prosegue.
- Token più lunghi di
MaxTokenLengthvengono saltati. - Header PDND mancanti non producono errori.
Nota operativa
La cattura degli header può comunque raccogliere dati sensibili se il tuo servizio (o i gateway) iniettano header applicativi contenenti informazioni personali. In produzione è raccomandata una allow-list stretta (vedi sotto).
Struttura dei pacchetti
Pdnd.Metadata
Astrazioni core e pipeline di estrazione, incluse utility di parsing PDND.Pdnd.Metadata.AspNetCore
Integrazione ASP.NET Core: middleware, accessor e tipi di binding per minimal API.
Quick start (ASP.NET Core)
1) Registra i servizi (production-first)
Preferisci un approccio allow-list: cattura solo ciò che serve (trace/correlation/forwarded + eventuali header PDND se decidi di persisterli come header raw).
builder.Services.AddPdndMetadata(options =>
{
options.CaptureAllHeaders = false;
// Recommended: allow-list only non-sensitive headers used for correlation/tracing
// (and any other header you explicitly govern).
options.HeaderAllowList.Add("traceparent");
options.HeaderAllowList.Add("tracestate");
options.HeaderAllowList.Add("baggage");
options.HeaderAllowList.Add("x-request-id");
options.HeaderAllowList.Add("x-correlation-id");
options.HeaderAllowList.Add("forwarded");
options.HeaderAllowList.Add("x-forwarded-for");
// PDND parsing (best-effort, no validation)
// Parsing reads the relevant headers even if you are not capturing raw headers.
options.ParsePdndVoucherFromAuthorizationBearer = true;
options.ParsePdndTrackingEvidence = true;
options.ParseDpopHeader = true;
options.ParseDigestHeader = true;
options.ParseContentDigestHeader = true;
options.ParseAgidJwtSignature = true;
// Do not store signed blobs
options.CaptureRawTrackingEvidenceHeader = false;
options.CaptureRawDpopHeader = false;
options.CaptureRawSignatureHeader = false;
// Guard-rail
options.MaxTokenLength = 16_384;
});
Modalità demo (solo local)
Se vuoi ispezionare gli header in sviluppo locale, puoi abilitare temporaneamente la cattura completa:
builder.Services.AddPdndMetadata(options =>
{
options.CaptureAllHeaders = true;
options.ParsePdndVoucherFromAuthorizationBearer = true;
options.ParsePdndTrackingEvidence = true;
options.ParseDpopHeader = true;
options.ParseDigestHeader = true;
options.ParseContentDigestHeader = true;
options.ParseAgidJwtSignature = true;
options.CaptureRawTrackingEvidenceHeader = false;
options.CaptureRawDpopHeader = false;
options.CaptureRawSignatureHeader = false;
options.MaxTokenLength = 16_384;
});
2) Aggiungi il middleware
Posizionalo prima del mapping degli endpoint così ogni request ottiene uno snapshot.
app.UsePdndMetadata();
3) Consuma i metadati (Controllers)
[HttpGet("/controller/metadata")]
public IActionResult Get([FromServices] IPdndMetadataAccessor accessor)
{
var md = accessor.Current;
return Ok(new
{
correlationId = md?.GetFirstValue(PdndMetadataKeys.CorrelationId),
voucherIss = md?.GetFirstValue(PdndMetadataKeys.PdndVoucherIss),
dpopHtu = md?.GetFirstValue(PdndMetadataKeys.PdndDpopHtu)
});
}
4) Consuma i metadati (Minimal APIs)
app.MapGet("/minimal/pdnd", (PdndCallerMetadataParameter pdnd) =>
{
var md = pdnd.Value;
return Results.Ok(new
{
voucher = new
{
iss = md.GetFirstValue(PdndMetadataKeys.PdndVoucherIss),
aud = md.GetFirstValue(PdndMetadataKeys.PdndVoucherAud),
purposeId = md.GetFirstValue(PdndMetadataKeys.PdndVoucherPurposeId)
},
trackingEvidence = new
{
kid = md.GetFirstValue(PdndMetadataKeys.PdndTrackingKid),
jti = md.GetFirstValue(PdndMetadataKeys.PdndTrackingJti)
},
dpop = new
{
htm = md.GetFirstValue(PdndMetadataKeys.PdndDpopHtm),
htu = md.GetFirstValue(PdndMetadataKeys.PdndDpopHtu)
},
digest = new
{
alg = md.GetFirstValue(PdndMetadataKeys.PdndDigestAlg)
}
});
});
Configurazione consigliata per produzione
Per i servizi in produzione, in genere è meglio decidere esplicitamente quali header catturare invece di collezionare tutto e filtrare dopo.
Approccio conservativo:
CaptureAllHeaders = false- mantieni una
HeaderAllowListstretta (trace + correlation + forwarded + solo ciò che governi esplicitamente) - mantieni
CaptureRawTrackingEvidenceHeader = false,CaptureRawDpopHeader = falseeCaptureRawSignatureHeader = false - valuta di disabilitare
CaptureRawDigestHeaderse non serve davvero - nelle pipeline di logging/audit evita di persistere l’intera mappa
itemsse non hai governance; preferisci loggare solo chiavi canoniche whitelistate
La libreria applica già la regola più importante di default: Authorization raw non viene mai memorizzato.
API di esempio
Il progetto di esempio serve per validare rapidamente l’integrazione, senza loggare token raw.
GET /minimal/pdnd
Restituisce sezioni voucher / trackingEvidence / dpop / digest / contentDigest / signature.GET /minimal/sanity
Verifica cheAuthorizationraw,DPoPraw, tracking evidence raw eAgid-JWT-Signatureraw non vengano catturati.
Esempio request (token fake sono sufficienti per verificare l’estrazione):
curl \
-H "Authorization: Bearer <jwt>" \
-H "Agid-JWT-Tracking-Evidence: <jws>" \
-H "DPoP: <dpop-jws>" \
-H "Digest: SHA-256=<base64>" \
-H "Content-Digest: sha-256=:<base64>:" \
-H "Agid-JWT-Signature: <jws>" \
http://localhost:5041/minimal/pdnd
Cosa questa libreria non fa
Questa è intenzionalmente una extraction layer, non una enforcement/security layer.
- Non valida firme JWT/JWS.
- Non applica regole di autorizzazione PDND.
- Non chiama API PDND (catalogo/registry/auth) per arricchire i metadati.
- Non logga token. Se aggiungi logging, limitati a chiavi canoniche
pdnd.*ed evita header raw.
Se ti serve validazione/enforcement, posizionala nel tuo layer auth (gateway/middleware di servizio) e usa Pdnd.Metadata solo come snapshot “audit-friendly” per osservabilità/diagnostica.
Schema chiavi canoniche
Per un riferimento completo e strutturato di tutte le 55+ chiavi canoniche di metadati estratte dalla libreria, consulta il documento PDND Metadata Schema.
Lo schema copre:
- Tutti i pattern di interoperabilita PDND (ID_AUTH, INTEGRITY, AUDIT)
- Mapping campi JWT/JWS per ogni tipo di token
- Riferimento opzioni di configurazione
- Considerazioni di sicurezza
Questo schema e pensato come riferimento di community per standardizzare l'estrazione dei metadati PDND nelle implementazioni .NET.
Riferimenti ufficiali PDND
- PDND Interoperabilità – Hub guide (developer.pagopa.it)
- Voucher (utilizzo) (developer.pagopa.it)
- Voucher con informazioni aggiuntive (Tracking Evidence) (developer.pagopa.it)
- Voucher FAQ / note Digest (developer.pagopa.it)
- Tracing – Manuale Operativo (developer.pagopa.it)
- Approfondimento DPoP (developer.pagopa.it)
- Release notes (developer.pagopa.it)
Autore e maintainer
| Francesco Del Re |
| Autore e maintainer |
Contribuire
Grazie per aver considerato di contribuire al codice sorgente! Se vuoi contribuire, fai un fork, applica le modifiche, esegui commit e apri una pull request così che i maintainer possano revisionare e fare merge nel branch principale.
Per iniziare con Git e GitHub
- Configurare Git
- Fare il fork del repository
- Aprire una issue se incontri un bug o hai suggerimenti per miglioramenti/nuove funzionalità
Licenza
Il codice sorgente di Pdnd.Metadata è distribuito con licenza MIT; consulta il file di licenza nel repository.
Contatti
Per qualsiasi informazione, contatta francesco.delre[at]protonmail.com.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Pdnd.Metadata (>= 1.0.0)
-
net8.0
- Pdnd.Metadata (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 37 | 4/3/2026 |