İtalyan Hükümet Kimliğinde OIDC'ye Doğru Evrim

On yıldan fazla bir süredir İtalyan dijital kimliği şu protokole dayanmaktadır: SAML2.0: Sağlam, iyi standardize edilmiş, ancak mobil öncesi dönemde tasarlandı. Akıllı telefonlara yönelik native uygulamaların patlaması ve Tek Sayfa Uygulamaların yaygınlaşmasıyla birlikte, SAML, büyük XML alışverişi, zayıf mobil destek, SPA'lara karmaşık entegrasyon gibi sınırlamalarını gösterdi.

Geçiş OpenID Bağlantısı (OIDC) kaçınılmazdı. Ocak 2023'te AgID şunu yayınladı: SPID'de OpenID Bağlantı Yönergeleri ve CIE'de OpenID Bağlantı YönergeleriOAuth 2.0'ı temel alan standardı, İtalyan hükümeti kimliğinin evriminin bir yolu olarak resmi hale getiriyor. PNRR hedefi, Mart 2026'ya kadar 16.500 İtalyan KA'nın tamamının SPID veya CIE aracılığıyla elektronik kimlik belirlemeyi benimsemesini gerektiriyor.

Neden PA için OpenID Connect ve SAML karşılaştırması

  • Hafif jetonlar: XML SAML onayı yerine JWT — yük %60-70 oranında azaltıldı
  • Mobil öncelikli: Yerel uygulamalar ve SPA'lar için tasarlanmış PKCE'li OAuth 2.0
  • Modern ekosistem: herhangi bir dil/çerçeve için mevcut kütüphaneler
  • Standartlaştırılmış federasyon: Otomatik güven zinciri için OpenID Federasyonu 1.0
  • EUDI Cüzdanına Doğru: OpenID4VP ve OpenID4VCI aynı OIDC temellerini kullanır

SPID/CIE OIDC Federasyonunun Mimarisi

SPID ve CIE için OIDC federasyonu aşağıdakilere dayanmaktadır: OpenID Federasyonu 1.0zincir yapımını otomatikleştiren bir standart kuruluşlar arasındaki güven. Bu, her SP'nin meta verileri manuel olarak değiştirmek zorunda olduğu SAML meta veri kaydının manuel modelini aşıyor Her IdP ile XML.

Federasyondaki kuruluşlar

  • Güven Çapası (TA): AgID, İtalyan federasyonunun güven dayanağıdır. Varlık Yapılandırmasını iyi bilinen uç noktaya yayınlar.
  • Orta seviye: Birden fazla RP'yi birleştiren AgID yetkili toplayıcılar (ör. bölgesel KA'lar, belediye toplayıcıları).
  • Güvenen Taraf (RP): SPID/CIE OIDC aracılığıyla kullanıcıların kimliğini doğrulayan uygulama.
  • Kimlik Sağlayıcı (OP): SPID sağlayıcıları (Poste Italiane, Aruba, InfoCert, vb.) veya İçişleri Bakanlığı'nın CIE IdP'si.

Varlık Yapılandırması ve Güven Zinciri

// Entity Configuration di un Relying Party
// Disponibile al well-known endpoint:
// GET https://my-service.comune.it/.well-known/openid-federation

{
  "iss": "https://my-service.comune.it",
  "sub": "https://my-service.comune.it",
  "iat": 1710000000,
  "exp": 1741536000,
  "jwks": {
    "keys": [
      {
        "kty": "EC",
        "kid": "rp-sig-key-2025",
        "crv": "P-256",
        "x": "...",
        "y": "...",
        "use": "sig"
      }
    ]
  },
  "metadata": {
    "openid_relying_party": {
      "application_type": "web",
      "client_id": "https://my-service.comune.it",
      "client_registration_types": ["automatic"],
      "redirect_uris": [
        "https://my-service.comune.it/callback"
      ],
      "response_types": ["code"],
      "grant_types": ["authorization_code"],
      "scope": "openid profile email",
      "token_endpoint_auth_method": "private_key_jwt",
      "id_token_signed_response_alg": "ES256",
      "subject_type": "pairwise",
      "contacts": ["tech-team@comune.it"]
    }
  },
  "authority_hints": [
    "https://registry.spid.gov.it"
  ]
}

PKCE ile Yetkilendirme Kodu Akışını Uygulama

SPID/CIE OIDC için önerilen akış:PKCE ile Yetkilendirme Kodu Akışı (Kod Değişimi için Kanıt Anahtarı, RFC 7636). PKCE, ele geçirilen yetkilendirme kodlarına karşı koruma sağlar ve mobil uygulamalar için zorunlu olup web uygulamaları için önerilir.

1. Adım: PKCE Oluşturma ve Yetkilendirme Talebi

// TypeScript - Authorization Request con PKCE

import crypto from "crypto";

function generatePKCE() {
  // code_verifier: stringa casuale 43-128 caratteri
  const codeVerifier = crypto.randomBytes(32)
    .toString("base64url");

  // code_challenge: SHA256 del verifier, base64url encoded
  const codeChallenge = crypto.createHash("sha256")
    .update(codeVerifier)
    .digest("base64url");

  return { codeVerifier, codeChallenge };
}

async function initiateLogin(req: Request, res: Response) {
  const { codeVerifier, codeChallenge } = generatePKCE();
  const state = crypto.randomBytes(16).toString("base64url");
  const nonce = crypto.randomBytes(16).toString("base64url");

  // Salva in sessione (server-side)
  req.session.pkce = { codeVerifier, state, nonce };

  // Costruisci l'Authorization Request
  const params = new URLSearchParams({
    response_type: "code",
    client_id: "https://my-service.comune.it",
    redirect_uri: "https://my-service.comune.it/callback",
    scope: "openid profile",
    // Per SPID LoA 2 (identità verificata con password forte)
    acr_values: "https://www.spid.gov.it/SpidL2",
    state,
    nonce,
    code_challenge: codeChallenge,
    code_challenge_method: "S256",
    // Parametri SPID specifici
    prompt: "login",
  });

  // Scopri il provider selezionato tramite OP Selector o discovery
  const opAuthEndpoint = await discoverOPEndpoint("https://idp.poste.it");

  res.redirect(`${opAuthEndpoint}?${params.toString()}`);
}

Adım 2: Geri Arama ve Token Değişimi

// TypeScript - Gestione callback e token exchange

async function handleCallback(req: Request, res: Response) {
  const { code, state, error } = req.query;
  const session = req.session.pkce;

  // Verifica state per prevenire CSRF
  if (state !== session.state) {
    return res.status(400).json({ error: "State mismatch" });
  }

  if (error) {
    return res.status(400).json({ error });
  }

  // Token Request - usa private_key_jwt per autenticarsi al token endpoint
  const clientAssertion = await createClientAssertion({
    iss: "https://my-service.comune.it",
    sub: "https://my-service.comune.it",
    aud: "https://idp.poste.it/oauth/token",
    jti: crypto.randomBytes(16).toString("hex"),
    iat: Math.floor(Date.now() / 1000),
    exp: Math.floor(Date.now() / 1000) + 60,
  });

  const tokenResponse = await fetch("https://idp.poste.it/oauth/token", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      code: code as string,
      redirect_uri: "https://my-service.comune.it/callback",
      client_id: "https://my-service.comune.it",
      client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
      client_assertion: clientAssertion,
      code_verifier: session.codeVerifier,
    }),
  });

  const tokens = await tokenResponse.json();

  // Verifica e decodifica l'ID Token
  const idToken = await verifyIdToken(tokens.id_token, {
    expectedNonce: session.nonce,
    expectedAudience: "https://my-service.comune.it",
  });

  // idToken.sub = identificatore opaco pairwise dell'utente
  // idToken.acr = livello di garanzia (LoA) ottenuto
  console.log("User authenticated:", idToken.sub);
  console.log("LoA achieved:", idToken.acr);
}

SPID ve CIE'de Güvence Düzeyleri (LoA)

Devlet kimliğinin en önemli yönlerinden biri, Güvence Düzeyi (LoA), bu, kimlik doğrulama işleminin ne kadar güvenilir olduğunu gösterir. SPID üç düzeyi tanımlar:

Seviye ACR URI'si Yöntem Tipik Kullanım
SpidL1 https://www.spid.gov.it/SpidL1 Kullanıcı adı + şifre Düşük riskli hizmetler, hassas olmayan veri danışmanlığı
SpidL2 https://www.spid.gov.it/SpidL2 Kullanıcı adı + şifre + OTP/push Standart PA hizmetleri (beyannameler, başvurular, ödemeler)
SpidL3 https://www.spid.gov.it/SpidL3 Sertifikalı fiziksel cihaz Yüksek riskli işlemler, nitelikli elektronik imza

İçin CIE (Elektronik Kimlik Kartı), garanti düzeyi her zaman LoA3'tür (maksimum). Belgenin ve PIN'in fiziksel olarak bulundurulmasını gerektirdiğinden CIE NFC çipini kullandı. Bu, CIE'yi bariz bir seçim haline getiriyor Güçlü kimlik doğrulama gerektiren hizmetler için.

UserInfo Uç Noktası ve SPID/CIE Nitelikleri

Oturum açtıktan sonra İtimat Eden Taraf, Erişim Simgesini kullanarak kullanıcının niteliklerini UserInfo Uç Noktasından alabilir. SPID OIDC'de mevcut olan nitelikler teknik profilde tanımlanmıştır:

// GET /userinfo
// Authorization: Bearer <access_token>

// Risposta UserInfo SPID
{
  "sub": "c5d9b2f3-1a4e-4b8d-9f2a-3e5c7d8f9b1a",  // pairwise pseudonimo
  "https://attributes.spid.gov.it/name": "Mario",
  "https://attributes.spid.gov.it/familyName": "Rossi",
  "https://attributes.spid.gov.it/fiscalNumber": "RSSMRA90A15H501Z",
  "https://attributes.spid.gov.it/dateOfBirth": "1990-01-15",
  "https://attributes.spid.gov.it/placeOfBirth": "Roma",
  "https://attributes.spid.gov.it/countyOfBirth": "RM",
  "https://attributes.spid.gov.it/idCard": "MRTMRA90A15H501Z",
  "https://attributes.spid.gov.it/address": {
    "formatted": "Via Roma 1, 00100 Roma RM"
  },
  "https://attributes.spid.gov.it/email": "mario.rossi@example.com",
  "https://attributes.spid.gov.it/mobilePhone": "+39 333 1234567",
  "acr": "https://www.spid.gov.it/SpidL2"
}

// ATTENZIONE: richiedere solo gli attributi strettamente necessari
// nell'Authorization Request tramite il parametro 'claims':
// "claims": {
//   "userinfo": {
//     "https://attributes.spid.gov.it/fiscalNumber": {"essential": true},
//     "https://attributes.spid.gov.it/name": null
//   }
// }

SPID Niteliklerinin Gizliliği ve Minimize Edilmesi

Kullanıcının vergi kodunu gerçek bir ihtiyaç olmadan talep etmek, GDPR'nin en aza indirme ilkesinin ihlalidir. AgID Yönergeleri, talep edilen her özelliğin, hizmet e-postasının belirli işlevselliği tarafından motive edilmesi gerektiğini belirtir. gizlilik politikasında belirtilmiştir. AgID denetimi sırasında istenen özelliklerin gerekçelendirilmemesi, akreditasyonun iptaline yol açabilir.

SPID/CIE OIDC için SDK ve Resmi Kitaplıklar

proje Geliştiriciler İtalya (developers.italia.it) çeşitli dillerde resmi SDK'lar sağlar SPID/CIE OIDC entegrasyonunu basitleştirmek için:

## SDK Ufficiali Developers Italia - SPID/CIE OIDC Federation

# Python (Django)
pip install spid-cie-oidc

# Configurazione in Django settings.py
INSTALLED_APPS = [
    ...
    "spid_cie_oidc.entity",
    "spid_cie_oidc.relying_party",
]

OIDCFED_DEFAULT_TRUST_ANCHOR = "https://registry.spid.gov.it"

OIDCFED_IDENTITY_PROVIDERS = {
    "spid": "https://registry.spid.gov.it",
    "cie": "https://idserver.servizicie.interno.gov.it"
}

# Configura automaticamente gli endpoint di federazione
# e gestisce la trust chain dinamicamente

# Java
# Maven: eu.italia.gov:spid-cie-oidc-java:latest

# .NET
# NuGet: AGID.SPID.OIDC

# Node.js (Express)
npm install spid-cie-oidc-node

# PHP
composer require italia/spid-php-lib

JARM: JWT Tabanlı Yetkilendirme Yanıt Modu

SPID/CIE OIDC Yönergeleri aşağıdakilerin kullanılmasını önerir: JARM (JWT Yetkilendirme Yanıt Modu) korumak yetkilendirme yanıtı. Geçmek yerine code e state sorgu parametreleri olarak açık metin olarak, JARM, yanıtı Kimlik Sağlayıcı tarafından imzalanan bir JWT'de kapsüller.

// Authorization Request con JARM
{
  "response_type": "code",
  "response_mode": "form_post.jwt",  // JARM mode
  "client_id": "https://my-service.comune.it",
  ...
}

// Risposta JARM dal IdP (form POST al redirect_uri)
// Il parametro 'response' contiene un JWT firmato:
// Header:
{ "alg": "ES256", "kid": "idp-key-2025" }
// Payload:
{
  "iss": "https://idp.poste.it",
  "aud": "https://my-service.comune.it",
  "code": "SplxlOBeZQQYbYS6WxSbIA",
  "state": "af0ifjsldkj",
  "iat": 1710000000,
  "exp": 1710000180
}

// Vantaggi JARM:
// 1. Autenticità: garantisce che la risposta venga dall'IdP corretto
// 2. Integrità: impossibile modificare code/state in transito
// 3. Non-repudiation: log auditabili con prova crittografica

Oturum Yönetimi ve Token Yenileme

Hükümet kimliğinin kritik bir yönü, oturumların doğru yönetimidir. Özel sektörden farklı olarak PA hizmetleri, oturum süresi ve oturum kapatmayla ilgili katı kısıtlamalara uymalıdır.

// Gestione sessione sicura per servizi PA

interface SessionConfig {
  maxAge: number;           // durata massima sessione in secondi
  inactivityTimeout: number; // timeout per inattività
  requireReauth: boolean;    // richiede riautenticazione per operazioni critiche
}

// Configurazione raccomandata per servizi PA
const SESSION_CONFIG: SessionConfig = {
  maxAge: 3600,          // 1 ora massimo (SPID raccomanda max 30 min per L2)
  inactivityTimeout: 900, // 15 min di inattività
  requireReauth: true     // operazioni di firma richiedono nuovo login
};

// Logout corretto: Single Logout (SLO) obbligatorio per SPID
async function handleLogout(req: Request, res: Response) {
  const session = req.session;

  // 1. Costruisci logout request per l'IdP
  const logoutRequest = createSignedLogoutRequest({
    iss: "https://my-service.comune.it",
    sub: session.userId,
    sid: session.idTokenHint,  // session ID dal ID Token
    aud: session.idpLogoutEndpoint,
    post_logout_redirect_uri: "https://my-service.comune.it/logout-complete",
  });

  // 2. Distruggi la sessione locale prima del redirect
  await req.session.destroy();

  // 3. Redirect all'IdP per SLO
  res.redirect(
    `${session.idpLogoutEndpoint}?` +
    `id_token_hint=${session.idToken}&` +
    `post_logout_redirect_uri=https://my-service.comune.it/logout-complete&` +
    `state=${generateState()}`
  );
}

AgID ile Akreditasyon ve Uyumluluk

SPID'yi hizmetine entegre etmek için İtimat Eden Tarafın AgID akreditasyon sürecinden geçmesi gerekir. OIDC için basitleştirilmiş prosedür 2023'ten itibaren kullanıma sunulacaktır:

  1. Teknik kayıt: Varlık Yapılandırması yapılandırması ve uç nokta doğrulaması /.well-known/openid-federation. AgID, otomatik araçlar aracılığıyla uyumluluğu doğrular.
  2. Fonksiyonel testler: Doğru uygulamayı doğrulamak için spid-sp-test (açık kaynak Python aracı) kullanma. Araç, Kimlik Sağlayıcıların davranışını simüle eder ve 200'den fazla test senaryosunu doğrular.
  3. GDPR uyumluluğu: gerekli her SPID özelliği için veri işlemenin belgelenmesi.
  4. Anlaşmanın imzalanması: SPID Teknik Kurallarının ve üyelik sözleşmesinin kabulü.
## Uso di spid-sp-test per verificare l'implementazione

# Installazione
pip install spid_sp_test

# Verifica metadata OIDC
spid_sp_test \
  --metadata-url https://my-service.comune.it/.well-known/openid-federation \
  --profile oidc_op

# Test flusso completo (richiede credenziali di test)
spid_sp_test \
  --metadata-url https://my-service.comune.it/.well-known/openid-federation \
  --authn-url https://my-service.comune.it/login/spid \
  --profile oidc_sp_public \
  --extra \
  --debug

# Output: report HTML con dettagli dei 200+ test
# File: report_<timestamp>.html

Yakınsamaya Doğru: SPID/CIE OIDC ve EUDI Cüzdanı

SAML'den OIDC'ye geçiş nihai hedef değildir. Ekosistem tam entegrasyona doğru ilerliyor ile EUDI Cüzdanı OpenID4VP aracılığıyla. proje iam-proxy-italia GitHub'da zaten gösteriyor bir IAM proxy'sinin aynı anda SAML 2.0, OIDC ve OpenID4VC'yi (IT-Wallet/EUDI Wallet için) nasıl destekleyebileceğini öğrenin.

Modern bir PA hizmeti için ideal mimari, üç akışın tamamını şeffaf bir şekilde desteklemelidir:

// Middleware di autenticazione multi-protocollo

interface AuthProvider {
  protocol: "saml2" | "oidc" | "openid4vp";
  name: string;
  endpoint: string;
}

const AUTH_PROVIDERS: AuthProvider[] = [
  {
    protocol: "oidc",
    name: "SPID",
    endpoint: "https://registry.spid.gov.it"
  },
  {
    protocol: "oidc",
    name: "CIE",
    endpoint: "https://idserver.servizicie.interno.gov.it"
  },
  {
    protocol: "openid4vp",
    name: "IT Wallet / EUDI Wallet",
    endpoint: "eudi-openid4vp://"
  }
];

function selectAuthFlow(userAgent: string, userPreference?: string): AuthProvider {
  // Logica di selezione basata su contesto
  if (userPreference === "wallet" || hasWalletApp(userAgent)) {
    return AUTH_PROVIDERS.find(p => p.protocol === "openid4vp")!;
  }
  // Default: CIE OIDC (LoA3 per impostazione predefinita)
  return AUTH_PROVIDERS.find(p => p.name === "CIE")!;
}

En İyi Uygulamalar ve Anti-Kalıplar

SPID/CIE OIDC için En İyi Uygulamalar

  • Web uygulamaları için bile her zaman PKCE'yi kullanın (yerel uygulamalar için zorunludur)
  • Yetkilendirme yanıtını korumak için JARM'ı uygulayın
  • RP imzalama anahtarlarını her 12 ayda bir (veya daha sık) değiştirin
  • Amerika sub dahili tanımlayıcı olarak ikili olarak — asla CF veya e-posta gibi nitelikler içermez
  • Tek Oturum Kapatmayı (SLO) uygulayın — SPID akreditasyonu için zorunludur
  • Güven zincirini 24 saate kadar önbelleğe alın (sonra güncelleyin)
  • Varlık Bildiriminin sona erme tarihini izleyin (genellikle 24 saat)

Kaçınılması Gereken Anti-Desenler

  • Kimlik Kartını kaydetmeyin localStorage veya HttpOnly olmayan çerezler
  • Kullanma response_mode=query (AMERİKA form_post o form_post.jwt)
  • Geçerli bir neden olmadan Erişim Simgesini ön uçta göstermeyin
  • Gereksiz SPID nitelikleri istemeyin (akreditasyon riski)
  • Doğrulamayı göz ardı etmeyin nonce Jeton Kimliğinde
  • Süresi dolmayan oturumları kullanmayın: PA oturumlarının zaman aşımları olması gerekir

Sonuçlar

OpenID Connect, İtalyan ve Avrupa devlet kimlik doğrulamasının geleceğini temsil ediyor. SAML'den OIDC'ye geçiş bu sadece teknik değil; daha modern bir ekosistemi, daha iyi araçları ve doğal bir yolu da beraberinde getiriyor EUDI Cüzdanı ile kendi kendine egemen kimliğe doğru.

Geliştiriciler bugün SPID/CIE OIDC'yi PKCE, JARM, otomatik federasyon gibi doğru kalıplarla uygulamaya başlıyor. ikili konu — OpenID4VP ve EUDI Cüzdan ile daha sonra entegrasyon için en uygun konumdadır. Bugün iyi yazılan kodun yarın yeniden yazılmasına gerek yoktur: bu, kamu dijital hizmetlerinin sürekliliğine yapılan bir yatırımdır.

GovTech serisi devam ediyor

Bir sonraki makalede Açık Veri API'lerinin tasarımını ve genel verilerin nasıl verimli bir şekilde yayınlanıp tüketileceğini keşfedin.