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
                    
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.AspNetCore" 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.AspNetCore" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Pdnd.Metadata.AspNetCore" />
                    
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.AspNetCore --version 1.0.0
                    
#r "nuget: Pdnd.Metadata.AspNetCore, 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.AspNetCore@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.AspNetCore&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Pdnd.Metadata.AspNetCore&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.

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