Pdnd.Metadata 1.0.0

dotnet add package Pdnd.Metadata --version 1.0.0
                    
NuGet\Install-Package Pdnd.Metadata -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Pdnd.Metadata" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pdnd.Metadata" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Pdnd.Metadata" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Pdnd.Metadata --version 1.0.0
                    
#r "nuget: Pdnd.Metadata, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Pdnd.Metadata@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Pdnd.Metadata&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Pdnd.Metadata&version=1.0.0
                    
Install as a Cake Tool

Pdnd.Metadata

License: MIT issues - pdndmetadata stars - pdndmetadata EN IT

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 Authorization raw, 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:

  1. 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)
  2. 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 Digest in 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-Signature per campi di integrità della richiesta
  3. 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.query
  • net.remote_ip, net.remote_port, net.local_ip, net.local_port, net.forwarded_for
  • correlation.id
  • trace.traceparent, trace.tracestate, trace.baggage
  • http.header.<lowercase-name> (solo se l’header capture è abilitato e l’header non è negato)

Nota sugli header forwarded: valori come Forwarded / X-Forwarded-For sono 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.iss
  • pdnd.voucher.sub
  • pdnd.voucher.aud (stringa normalizzata; può originare da un array JWT)
  • pdnd.voucher.jti
  • pdnd.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.typ
  • pdnd.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.alg
  • pdnd.digest.value

Riferimento: note digest nelle FAQ voucher. (developer.pagopa.it)

DPoP (da DPoP)
  • pdnd.dpop.alg, pdnd.dpop.kid, pdnd.dpop.typ
  • pdnd.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.alg
  • pdnd.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 MaxTokenLength vengono 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 HeaderAllowList stretta (trace + correlation + forwarded + solo ciò che governi esplicitamente)
  • mantieni CaptureRawTrackingEvidenceHeader = false, CaptureRawDpopHeader = false e CaptureRawSignatureHeader = false
  • valuta di disabilitare CaptureRawDigestHeader se non serve davvero
  • nelle pipeline di logging/audit evita di persistere l’intera mappa items se 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 che Authorization raw, DPoP raw, tracking evidence raw e Agid-JWT-Signature raw 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

Autore e maintainer

Francesco Del Re
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

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Pdnd.Metadata:

Package Downloads
Pdnd.Metadata.AspNetCore

ASP.NET Core integration for Pdnd.Metadata — middleware, DI registration, model binding, and Minimal API support for PDND metadata extraction.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 33 4/3/2026