İçeriğe geç
academia.sh

Ders 14 / 19

Belirteç Tabanlı Kimlik Doğrulama

Durumsuz oturumda kimliğe dair her şey belirtecin taşıdığı iddialarda durur; sunucu tarafında hiçbir oturum kaydı yok. Bir yetki sorusunun bir açıklamadan mı yoksa kaynaktaki bir karşılaştırmadan mı yanıtlandığı koşturularak ayrılır; sınırlayıcı ölçüm, iptal edilmiş bir belirtecin doğrulayıcı hiçbir iptal listesine bakmadığı için süresi dolana kadar kaç adım geçerli sayılmaya devam ettiğini sayıyla gösterir.

İçindekiler

Önceki ders çağıranın rolünü hazır bir dize olarak aldı ve bu dizenin nereden geldiğini hiç sormadı. Bu ders tam o soruyu soruyor. Bir sunucu, bir çağıranın kim olduğunu iki yoldan birinden bilebilir: ya her istekte o çağırana ait bir kaydı kendi tarafında tutar, ya da kimliğe dair her şeyi çağıranın taşıdığı bir belirteçte saklar ve kendi tarafında hiçbir şey tutmaz. İkincisi durumsuz oturum: sunucunun belleğinde çağıranla ilgili sıfır kayıt var, her isteğin kimliği o isteğin kendi içinde geliyor. Bu ders belirteci modelliyor — gerçek bir anahtar, gerçek bir imza algoritması ya da gerçek bir kriptografi yordamı yazmadan — ve iki şeyi ölçüyor: belirtecin taşıdığı iddia (belirteç) sayısı, ve bir yetki sorusunun yanıtının kaynakta bir açıklamadan mı yoksa bir çağrıdan mı geldiği. Sınırlayıcı ölçüm en sona bırakılıyor, çünkü durumsuzluğun bir bedeli var ve bu bedel ancak belirtecin ömrü boyunca koşturularak görülüyor.

Oturum tabanlı bir yaklaşımda sunucu her çağıran için bir kayıt tutar; kaydı silmek çağıranı anında geçersiz kılar, çünkü her istek zaten o kayda bakar. Durumsuz yaklaşım bu bakışı hiç yapmaz — kimliğin kanıtı her istekle birlikte gelir, sunucu tarafında sorgulanacak bir kayıt yoktur. Bu fark yalnız bir uygulama ayrıntısı değil, bu dersin ölçtüğü şeyin tam kendisi.

Belirtecin Taşıdığı İddialar

Modellenen belirteç iki alan taşıyor: bir konu (çağıranın kimliği) ve bir iddialar haritası — konu hakkında taşınan her bilgi bu haritada bir anahtar-değer çifti. Üçüncü alan bir geçerlilik sonu, ama bu gerçek bir zaman damgası değil: dersin ilerleyen bölümünde kullanılacak, adım sayan bir tam sayı. Gerçek saat, gerçek süre ya da gerçek bir imza yok; belirtecin kendisi sıradan bir veri taşıyıcısı olarak modelleniyor.

// Belirtec.java — kimlige dair her seyi tasiyan durumsuz veri tasiyicisi; gecerlilikSonu gercek zaman degil, adim sayan bir tam sayi (yardimci kaynak, main yok)
import java.util.*;

record Belirtec(String konu, Map<String, String> iddialar, int gecerlilikSonu) { }

class Dogrulayici {
    // durumsuz dogrulama: yalniz belirtecin kendi alanlarina ve verilen adima bakar,
    // hicbir paylasilan duruma (iptal listesi, oturum deposu) erismiyor.
    static boolean gecerliMi(Belirtec b, int suAn) {
        return suAn <= b.gecerlilikSonu();
    }

    static void goster(String etiket, Object deger) {
        System.out.printf("%-42s: %s%n", etiket, deger);
    }
}
// IddiaSayisi.java — iki belirtecin tasidigi iddia sayisi sayiliyor; sunucu tarafinda tutulan oturum kaydi sayisi sifir
import java.util.*;

public class IddiaSayisi {
    public static void main(String[] args) {
        Belirtec misafir = new Belirtec("kullanici-7", Map.of("rol", "misafir"), 10);
        Belirtec yonetici = new Belirtec("kullanici-2",
                Map.of("rol", "yonetici", "departman", "IT", "seviye", "3"), 10);

        Dogrulayici.goster("misafir belirteci, tasidigi iddia sayisi", misafir.iddialar().size());
        Dogrulayici.goster("yonetici belirteci, tasidigi iddia sayisi", yonetici.iddialar().size());
        Dogrulayici.goster("sunucu tarafinda tutulan oturum kaydi sayisi", 0);
    }
}
misafir belirteci, tasidigi iddia sayisi  : 1
yonetici belirteci, tasidigi iddia sayisi : 3
sunucu tarafinda tutulan oturum kaydi sayisi: 0

misafir bir iddia taşıyor, yonetici üç. Bu sayı sabit değil — her belirteç kendi taşıdığı bilgi kadar ağır, ve sunucu tarafında bu bilgiyi tekrar tutan hiçbir yapı yok. GT6. Belirteç, sunucu tarafında hiçbir oturum kaydı tutulmadan, kimliğe dair bütün bilgiyi kendi iddiaları içinde taşır; bu, durumsuz oturumun tanımıdır. GT7. Taşınan iddia sayısı belirteçten belirtece değişebilir, ama sunucu tarafında tutulan kayıt sayısı her zaman sıfırdır — önceki derste ölçülen Bekci’nin ucNoktalar haritası gibi bir yapı burada yok, çünkü ölçülecek bir çağıran durumu zaten bulunmuyor.

Gerçek bir belirteç sistemi iddiaları bir imzayla korur — belirtecin içeriği değiştirilmiş mi diye bakan bir doğrulama adımı. Bu ders o adımı yazmıyor; imza, anahtar ve kriptografi yordamları M24/K04 Kimlik, Erişim ve Kriptografi kursunda kuruldu ve burada tekrarlanmıyor. Burada Belirtec sıradan bir kayıt (record), imzasız ve doğrudan üretilmiş; ölçülen şey imzanın kendisi değil, imza doğru olduğunda bile geriye kalan iki soru — iddia ne kadar bilgi taşıyor, ve o bilgi nasıl okunuyor.

Durumsuzluğun bu konudaki asıl kazancı, kimliği doğrulayan tarafın hiçbir paylaşılan kayda ihtiyaç duymaması. Bir çağrıyı hangi bileşenin karşıladığı önemsiz hâle geliyor, çünkü her bileşen belirteci tek başına, kendi elindeki bilgiyle doğrulayabiliyor — bir öncekinin tuttuğu bir kaydı sormasına gerek yok. Bu özellik ilerideki iki derste tekrar karşımıza çıkacak: dağıtık yapılandırma dersinde birden çok bileşenin aynı değeri görüp görmediği sorgulanacak, servis keşfi dersinde bir çağrının hangi bileşene ulaştığı hiç sabit olmayacak. Durumsuz kimlik, bu değişkenliğin bir sorun çıkarmamasının nedenlerinden biri.

Doğrulamanın Kaynağı: Açıklama mı Çağrı mı

Bir belirtecin taşıdığı iddiaların doğru olup olmadığı ayrı bir soru; bu ders yalnız iddiaların okunma biçimini ölçüyor — “rol iddiası yönetici mi” sorusunun yanıtı nereden geliyor? İki yol modelleniyor. Birincisi bir açıklama: yönteme konan @GerekliIddia işareti, gerekli anahtarı ve beklenen değeri taşıyor, onu okuyan ve karşılaştıran taraf çağıran değil, denetim sınıfının kendisi.

// GerekliIddia.java — bir yontemin gecmesi icin belirtecte hangi iddianin hangi degeri tasimasi gerektigini belirten aciklama tipi (yardimci kaynak, main yok)
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface GerekliIddia { String ad(); String deger(); }
// IddiaDenetimi.java — aciklamayi okuyup belirtecin ilgili iddiasiyla karsilastiran denetim (yardimci kaynak, main yok)
import java.lang.reflect.*;

class IddiaDenetimi {
    static boolean karsilarMi(Method m, Belirtec b) {
        GerekliIddia g = m.getAnnotation(GerekliIddia.class);
        if (g == null) return true;
        return g.deger().equals(b.iddialar().get(g.ad()));
    }
}
// GizliUclar.java — panel yontemi uzerindeki isaret, hangi iddianin gerekli oldugunu soyluyor (yardimci kaynak, main yok)
class GizliUclar {
    @GerekliIddia(ad = "rol", deger = "yonetici")
    String panel() { return "panel-verisi"; }
}

İkinci yol kaynakta yazılı bir karşılaştırma; hiçbir işaret okunmuyor, hiçbir yansıma çalışmıyor.

// ElleDogrulama.java — ayni soru, kaynakta yazili bir karsilastirmadan yanitlaniyor (yardimci kaynak, main yok)
class ElleDogrulama {
    static boolean yoneticiMi(Belirtec b) {
        return "yonetici".equals(b.iddialar().get("rol"));
    }
}
// DogrulamaKaynagi.java — ayni iki belirtecle, aciklama temelli ve cagri temelli denetim ayni sonucu ureterek karsilastiriliyor
import java.lang.reflect.*;
import java.util.*;

public class DogrulamaKaynagi {
    public static void main(String[] args) throws Exception {
        Belirtec misafir = new Belirtec("kullanici-7", Map.of("rol", "misafir"), 10);
        Belirtec yonetici = new Belirtec("kullanici-2", Map.of("rol", "yonetici"), 10);

        Method panel = GizliUclar.class.getDeclaredMethod("panel");

        Dogrulayici.goster("aciklama: panel, misafir belirteci", IddiaDenetimi.karsilarMi(panel, misafir));
        Dogrulayici.goster("aciklama: panel, yonetici belirteci", IddiaDenetimi.karsilarMi(panel, yonetici));
        Dogrulayici.goster("cagri: elleDogrulama, misafir belirteci", ElleDogrulama.yoneticiMi(misafir));
        Dogrulayici.goster("cagri: elleDogrulama, yonetici belirteci", ElleDogrulama.yoneticiMi(yonetici));
    }
}
aciklama: panel, misafir belirteci        : false
aciklama: panel, yonetici belirteci       : true
cagri: elleDogrulama, misafir belirteci   : false
cagri: elleDogrulama, yonetici belirteci  : true

Dört satırın sonucu ikişer ikişer birebir aynı; IddiaDenetimi.karsilarMi ile ElleDogrulama.yoneticiMi aynı iki belirteç için aynı iki yanıtı veriyor. GT8. Aynı “rol yönetici mi” sorusu bir açıklamadan okunarak yanıtlanabiliyor: panel yönteminin kaynağında ne “rol” sözcüğü ne bir karşılaştırma geçiyor, karar @GerekliIddia işaretinde duruyor. GT9. Aynı soru kaynakta yazılı bir karşılaştırmadan da yanıtlanabiliyor: yoneticiMi yönteminin ilk satırı iddialar().get("rol") çağrısını ve karşılaştırmayı doğrudan taşıyor. İki kaynak aynı sonucu üretiyor, ama GizliUclar sınıfının kaynağını okuyan biri “yönetici” sözcüğünü hiç görmezken, ElleDogrulama sınıfının kaynağını okuyan biri onu ilk satırda buluyor.

IddiaDenetimi.karsilarMi yönteminin bir de üçüncü hâli var: @GerekliIddia işareti hiç yoksa yöntem doğrudan true döner — önceki dersteki varsayılan-açık kurulumun aynısı, burada tek satırlık bir kısayolla. Bu, açıklama ile çağrı arasındaki asıl farkı gösteriyor: açıklama tabanlı denetim bütün GizliUclar sınıfı için tek bir yerde tanımlı, yeni bir yöntem eklendiğinde default olarak izin veriyor ve gerekiyorsa üzerine işaret konuyor. Çağrı tabanlı denetimde ise her yeni yöntem kendi karşılaştırmasını kendi yazmak zorunda; bir yöntem bu satırı unutursa, unutulduğu hiçbir yerde görünmez — kaynak eksiksiz derlenir, çalışır, ve denetimsiz kalır.

Durumsuzluğun Bedeli: İptal Edilmiş Bir Belirtecin Ömrü

Dogrulayici.gecerliMi yalnız iki şeye bakıyor: belirtecin kendi gecerlilikSonu alanına ve kendisine verilen suAn değerine. Bu, dersin en sınırlayıcı ölçümünü doğuruyor: bir belirteç “iptal edilse” bile, doğrulayıcının bakacağı hiçbir iptal listesi yoksa, iptal kaydı belirtecin geçerliliğini hiç etkilemiyor. Uygulama kendi tarafında bir iptal listesi tutabilir, ama gecerliMi bu listeye hiç erişmiyor — erişseydi, durumsuz olmaktan çıkar, her çağrıda paylaşılan bir yapıya bakan bir doğrulayıcıya dönerdi.

// IptalVeGecerlilik.java — iptal edilen belirtec, dogrulayici iptal listesine hic bakmadigi icin suresi dolana kadar gecerli sayilmaya devam ediyor
import java.util.*;

public class IptalVeGecerlilik {
    public static void main(String[] args) {
        Belirtec belirtec = new Belirtec("kullanici-9", Map.of("rol", "calisan"), 10);
        Set<String> iptalEdilenler = new HashSet<>();

        Dogrulayici.goster("iptalden once, an=0, gecerli mi", Dogrulayici.gecerliMi(belirtec, 0));

        iptalEdilenler.add(belirtec.konu());
        Dogrulayici.goster("konu iptal listesinde mi", iptalEdilenler.contains(belirtec.konu()));

        int gecerliKalanAdim = 0;
        for (int an = 1; an <= 15; an++) {
            if (Dogrulayici.gecerliMi(belirtec, an)) gecerliKalanAdim++;
        }
        Dogrulayici.goster("iptalden sonra dogrulayicinin gecerli saydigi adim sayisi", gecerliKalanAdim);
        Dogrulayici.goster("an=11, gecerli mi (sure doldu)", Dogrulayici.gecerliMi(belirtec, 11));
    }
}
iptalden once, an=0, gecerli mi           : true
konu iptal listesinde mi                  : true
iptalden sonra dogrulayicinin gecerli saydigi adim sayisi: 10
an=11, gecerli mi (sure doldu)            : false

iptalEdilenler kümesi belirtec.konu()’yu tutuyor — uygulama bu konuyla ilgili bir karar verdi. Ama Dogrulayici.gecerliMi bu kümenin varlığından habersiz; ona hiç parametre olarak verilmiyor, hiç sorgulanmıyor. GT10. Durumsuz doğrulama yalnız belirtecin kendi alanlarına ve verilen adıma bakar; iptal listesi gibi paylaşılan bir duruma erişimi yoktur. GT11. İptal edilmiş bir belirteç, doğrulayıcı iptal listesine hiç bakmadığı için süresi dolana kadar geçerli sayılmaya devam eder — bu derste bu süre on adım, ve on birinci adımda gecerlilikSonu aşıldığı için doğrulama kendiliğinden false dönüyor. On adımlık bu pencere belirtecin kendi gecerlilikSonu değerinden geliyor; kısa tutulan bir geçerlilik süresi bu pencereyi daraltır, ama sıfıra indirmez. Bunu iddia olarak bırakmadan koşturarak doğrulamak için aynı ölçüm daha kısa bir geçerlilik süresiyle tekrarlanıyor.

// KisaPencere.java — gecerlilik suresi kisaltilinca, iptalden sonra gecerli sayilan adim sayisi da ayni oranda kisaliyor
import java.util.*;

public class KisaPencere {
    public static void main(String[] args) {
        Belirtec kisaOmurlu = new Belirtec("kullanici-11", Map.of("rol", "calisan"), 3);

        int gecerliKalanAdim = 0;
        for (int an = 1; an <= 15; an++) {
            if (Dogrulayici.gecerliMi(kisaOmurlu, an)) gecerliKalanAdim++;
        }
        Dogrulayici.goster("gecerlilikSonu=3 belirtec, iptalden sonra gecerli sayilan adim", gecerliKalanAdim);
    }
}
gecerlilikSonu=3 belirtec, iptalden sonra gecerli sayilan adim: 3

gecerlilikSonu on yerine üç verildiğinde, iptalden sonra geçerli sayılan adım sayısı da on yerine üç oluyor — pencere daralıyor, orantılı biçimde. Ama sıfıra hiç inmiyor, çünkü gecerliMi çağrısının kendisi hâlâ yalnız bir sayı karşılaştırması; iptali anında görebilmesi için doğrulayıcının paylaşılan bir duruma bakması gerekirdi, ve o bakışı eklemek onu artık durumsuz olmaktan çıkarırdı. Bu, dersin sınırlayıcı ölçümü: durumsuzluk bedelsiz değil, bedeli iptalin gecikmesiyle ölçülüyor, ve bu gecikme — geçerlilik süresi kısaltıldıkça küçülse de — hiçbir zaman sıfır olmuyor.

Dersin üç ölçümü yan yana konduğunda aynı örüntü tekrar ediyor: kaynakta duran ya da hiç durmayan bir bilgi, ancak koşturularak sayıya dönüşüyor.

Ölçüm Bu derste gözlenen
iddia sayısı (misafir / yönetici) 1 / 3
doğrulama kaynağı (açıklama / çağrı) ikisi de aynı sonucu üretiyor
iptalden sonra geçerli kalan adım (geçerlilik süresi 10) 10
iptalden sonra geçerli kalan adım (geçerlilik süresi 3) 3

Son iki satır aynı düzeneği iki ayrı parametreyle koşturuyor ve bedelin sabit değil, geçerlilik süresiyle orantılı olduğunu gösteriyor — bu da kaynakta yazılı bir sayı değil, iki koşumun karşılaştırılmasıyla ortaya çıkan bir ilişki.

Özet

  • Belirteç, sunucu tarafında hiçbir oturum kaydı tutulmadan kimliğe dair bilgiyi kendi iddiaları içinde taşır; taşınan iddia sayısı belirteçten belirtece değişir.
  • Bir yetki sorusu bir açıklamadan (@GerekliIddia) okunarak yanıtlanabilir; karar kaynakta hiçbir çağrı ifadesi doğurmaz.
  • Aynı soru kaynakta yazılı bir karşılaştırmadan (çağrıdan) da yanıtlanabilir; iki kaynak aynı sonucu üretir, farklı yerden.
  • Durumsuz doğrulama yalnız belirtecin kendi alanlarına ve verilen ana bakar; paylaşılan hiçbir duruma (iptal listesi gibi) erişimi yoktur.
  • İptal edilmiş bir belirteç, doğrulayıcı iptal listesine hiç bakmadığı için süresi dolana kadar geçerli sayılmaya devam eder; bu, kaç adım sürdüğü sayılabilen bir bedeldir.

Sonraki Adım

Bu iki ders yetkilendirme kararının kaynağını tek bir çağrı ya da tek bir belirteç üzerinden ölçtü. Bir kabın gerçekte kaç bileşeni ayağa kaldırdığı, hangi testin hangi parçayı kurduğu henüz hiç sorulmadı. Sıradaki ders aynı kabı bir test ortamına koyuyor ve iki kurulumu yan yana sayıyor: dilim testi kaç bileşeni ayağa kaldırıyor, tam bağlam testi kaç bileşeni — ve dilimin dışında kalan bir açıklamaya ne oluyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat