İçeriğe geç
academia.sh

Ders 13 / 19

Kimlik Doğrulama ve Yetkilendirme

Yetkilendirme kararı bir açıklamadan mı geliyor, kabın varsayılanından mı, yoksa kaynakta yazılı bir denetim ifadesinden mi — filtre zinciri modellenerek üçü ayrılır; hiçbir kural taşımayan bir uç noktanın açık mı kapalı mı olduğunun, kabın kurulması sırasında verilen tek bir parametreyle belirlendiği ve bu farkın kaynakta hiç görünmediği koşturularak gösterilir.

İçindekiler

Önceki konunun son dersi işlem sınırının kaynakta nasıl açıldığını ölçtü: sınırı bir açıklama koyuyordu, ve bileşenin kendi içinden yaptığı çağrı bu sınırı hiç görmüyordu — vekil aradan çıkınca açıklama da aradan çıkıyordu. Bu konu aynı soruyu güvenlik, test ve dağıtık kurulum için soruyor; ilk durak yetkilendirme. Bir uç noktaya kimin erişebileceğini kaynakta arayan biri çoğu zaman hiçbir şey bulmaz: ne bir denetim satırı, ne bir rol karşılaştırması. Karar ya bir açıklamadan gelir ya da hiçbir yerden — nesne kabının kendi varsayılanından. Kimlik doğrulamanın ve yetkilendirmenin kavramları — kimin kim olduğu, hangi yetkinin nasıl temsil edildiği, rol ile izin arasındaki fark — M16/K04 Kimlik Doğrulama ve Yetkilendirme ile M24/K04 Kimlik, Erişim ve Kriptografi kurslarında kuruldu ve burada tekrarlanmıyor; bu ders yalnız kararın hangi düzenekle verildiğini ölçüyor. K06’nın sorduğu soru bu konuda da değişmiyor: bu davranışı kaynakta bir çağrı mı, bir açıklama mı doğurdu, yoksa hiçbiri mi? Bir filtre zinciri modelleniyor ve üç kaynak ayrılıyor: çağrı, açıklama, varsayılan. En tehlikelisi üçüncüsü, çünkü kabın varsayılanı kaynakta hiçbir iz bırakmıyor; aynı kaynak metni iki farklı varsayılanla iki farklı güvenlik duruşu veriyor ve bu ders bunu koşturarak gösteriyor.

Bu dersin sınırları da baştan çiziliyor: kimlik doğrulama (çağıranın kim olduğunu kanıtlaması) ile yetkilendirme (kanıtlanmış kimliğin neyi yapabileceğine karar verilmesi) arasındaki ayrım M16/K04’te kuruldu; bu ders çağıranın kimliğini zaten çözülmüş bir rol dizesi olarak alıyor ve yalnız yetkilendirme kararının kaynağını ölçüyor — kimliğin nasıl kanıtlandığı sıradaki dersin konusu. Gerçek bir soket, gerçek bir istek gövdesi ve gerçek bir oturum deposu yok; filtre zinciri ve kararı okuyan nesne kabı tek başına modelleniyor.

Filtre Zincirinin Uyguladığı Karar

Modellenen nesne kabı, @UcNokta işaretli yöntemleri bir yol adına eşleyen küçük bir sınıf; bu, framework-core konusundaki nesne kabıyla aynı düzenek — orada nesneyi kuran açıklamalar ölçüldü, burada aynı kabın bir isteği hangi kurala göre geçirdiği ölçülüyor. Bekci kurulurken hedef nesnenin bütün yöntemlerini bir kez tarıyor ve @UcNokta taşıyanları bir yol adına eşliyor; bu tarama kuruluş anında bir kez oluyor, her çağrıda yeniden yapılmıyor. Çağrı geldiğinde tek halkalı bir filtre zinciri devreye giriyor: yöntemde @Yetki işareti varsa çağıranın rolünü işaretteki rolle karşılaştırıyor; işaret yoksa kabın kurulurken verilen varsayilanAcikMi alanına bakıyor. Gerçek bir ağ isteği, gerçek bir oturum ya da gerçek bir sunucu yok — zincirin kendisi ve kararı okuyan yansıma var.

// Bekci.java — istegi filtre zincirinden gecirip yetki kararini kaynaktaki isarete ya da kabin varsayilanina gore veren kucuk bir nesne kabi (yardimci kaynak, main yok)
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface UcNokta { String yol(); }

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD)
@interface Yetki { String rol(); }

class Bekci {
    final Object hedef;
    final boolean varsayilanAcikMi;
    final Map<String, Method> ucNoktalar = new LinkedHashMap<>();

    Bekci(Object hedef, boolean varsayilanAcikMi) {
        this.hedef = hedef;
        this.varsayilanAcikMi = varsayilanAcikMi;
        for (Method m : hedef.getClass().getDeclaredMethods()) {
            UcNokta u = m.getAnnotation(UcNokta.class);
            if (u != null) ucNoktalar.put(u.yol(), m);
        }
    }

    // filtre zincirinin tek halkasi: aciklama varsa onu okur, yoksa kabin varsayilanina doner.
    boolean izinVer(String yol, String cagiranRolu) {
        Method m = ucNoktalar.get(yol);
        if (m == null) return false;
        Yetki y = m.getAnnotation(Yetki.class);
        if (y == null) return varsayilanAcikMi;
        if (y.rol().equals("herkes")) return true;
        return y.rol().equals(cagiranRolu);
    }

    String cagir(String yol, String cagiranRolu) throws Exception {
        if (!izinVer(yol, cagiranRolu)) return "engellendi";
        Method m = ucNoktalar.get(yol);
        m.setAccessible(true);
        return (String) m.invoke(hedef);
    }

    static void gozle(String davranis, String kaynak, Object sonuc) {
        System.out.printf("%-40s %-11s: %s%n", davranis, kaynak, sonuc);
    }
}

class Uclar {
    @UcNokta(yol = "/panel") @Yetki(rol = "yonetici")
    String panel() { return "panel-verisi"; }

    @UcNokta(yol = "/durum")
    String durum() { return "calisiyor"; }

    @UcNokta(yol = "/surum") @Yetki(rol = "herkes")
    String surum() { return "surum-3"; }
}

Uclar sınıfının kaynağında izinVer yöntemini çağıran, ya da rolleri karşılaştıran hiçbir satır yok. panel yönteminin üzerinde duran @Yetki(rol = "yonetici") yalnız bir işaret; onu okuyan ve uygulayan taraf Bekci. Açıklama tipleri @Retention(RetentionPolicy.RUNTIME) ile işaretli, çünkü kararı derleyici değil çalışma zamanında yansıma veriyor — derleme sınıf yolundan silinen bir açıklama, Bekci’nin okuyacağı hiçbir şey bırakmaz; hedef ElementType.METHOD olduğu için işaret yalnız yöntemlere konabiliyor, sınıfın kendisine ya da alanlarına taşınamıyor. GT1. Filtre zincirinin tek halkası yetki açıklamasını okuyup çağıranın rolüyle karşılaştırır; açıklama yoksa kabın kendi varsayılanına döner. GT2. Yetki açıklaması taşıyan bir uç noktada kararı kaynakta hiçbir çağrı ifadesi doğurmaz — karar açıklamadan gelir.

// FiltreKarari.java — yetki aciklamasi olan bir uc noktada karar, cagiranin rolunu aciklamayla karsilastiran filtre zincirinden geliyor
public class FiltreKarari {
    public static void main(String[] args) throws Exception {
        Bekci bekci = new Bekci(new Uclar(), true);
        Bekci.gozle("panel, cagiran yonetici", "aciklama", bekci.cagir("/panel", "yonetici"));
        Bekci.gozle("panel, cagiran calisan", "aciklama", bekci.cagir("/panel", "calisan"));
    }
}
panel, cagiran yonetici                  aciklama   : panel-verisi
panel, cagiran calisan                   aciklama   : engellendi

Aynı bekci nesnesi, aynı cagir çağrısı, aynı /panel yolu — değişen tek şey argüman olarak verilen rol. Yönetici rolüyle gelen çağrı yönteme ulaşıyor ve gövdesini döndürüyor; çalışan rolüyle gelen çağrı yöntemi hiç çalıştırmadan engellendi sonucunu alıyor. Karar panel yönteminin gövdesinde değil, üzerindeki işarette duruyor ve işareti okuyan taraf Bekci’nin kendisi; panel yöntemi kendi başına ne yönetici sözcüğünü tanır ne kimin çağırdığını sorar. Yöntem yeniden yazılmadan, üzerindeki işaret değiştirilerek — örneğin rol = "calisan" yapılarak — aynı davranış farklı bir role açılabilir; bu değişiklik gövdeye hiç dokunmaz.

Yol eşlemesi Bekci kurulurken bir kez çıkarılıyor; cagir her seferinde yeniden yansıma taraması yapmıyor, önceden çıkarılmış ucNoktalar haritasına bakıyor. Tanınmayan bir yol istendiğinde izinVer doğrudan false döner — bu da bir çağrı değil, kabın kendi kuralı: haritada karşılığı olmayan her yol, hiçbir açıklama okunmadan reddedilir. Yani üçüncü bir varsayılan daha var, ama bu kez yönü sabit: bilinmeyen yol her koşulda kapalı, varsayilanAcikMi alanından bağımsız. Bilinen ile bilinmeyen yol arasındaki bu asimetri kaynakta da görünmüyor; yalnızca ucNoktalar haritasının içeriğine bakarak anlaşılabiliyor.

Kural Yazılmadığında: Varsayılanın Yönü

Uclar sınıfındaki durum yönteminin üzerinde hiçbir yetki işareti yok. Bu, kaynağı okuyan birinin hiçbir şey bulamayacağı durum — ve tam da bu yüzden en sınırlayıcı ölçüm burada. izinVer yöntemi işaret bulamadığında varsayilanAcikMi alanına bakıyor; bu alan Bekci kurulurken verilen bir kurucu parametresi, kaynağın hiçbir yerinde görünmeyen bir değer. İki kurulum arasındaki fark yalnız bu tek boolean değeri: hiçbir sınıf yeniden yazılmıyor, hiçbir açıklama eklenmiyor.

// VarsayilanYonu.java — kaynagi degismeyen bir uc nokta, kabin kurulurken verilen tek bir parametreyle iki ayri sonuc uretiyor
public class VarsayilanYonu {
    public static void main(String[] args) throws Exception {
        Bekci acikBekci = new Bekci(new Uclar(), true);
        Bekci kapaliBekci = new Bekci(new Uclar(), false);

        Bekci.gozle("durum, acik-kurulumda", "varsayilan", acikBekci.cagir("/durum", "misafir"));
        Bekci.gozle("durum, kapali-kurulumda", "varsayilan", kapaliBekci.cagir("/durum", "misafir"));
        System.out.println("kaynak birebir ayni: Uclar.durum() hicbir yetki isareti tasimiyor");
    }
}
durum, acik-kurulumda                    varsayilan : calisiyor
durum, kapali-kurulumda                  varsayilan : engellendi
kaynak birebir ayni: Uclar.durum() hicbir yetki isareti tasimiyor

Uclar.java dosyası iki koşum arasında tek bir karakter değişmedi; acikBekci ile kapaliBekci aynı sınıftan kuruldu. Buna rağmen misafir rolüyle yapılan aynı çağrı bir kurulumda veriyi döndürüyor, ötekinde reddediliyor. GT3. Yetki açıklaması taşımayan bir uç noktada karar kabın kendi varsayılanından gelir; kaynak metni bu iki yönden hiçbirini göstermez. GT4. Aynı kaynak, yeniden derlenmeden, yalnız kabın kurulması sırasında verilen bir kurucu parametresiyle iki farklı güvenlik duruşu üretebilir — bu, dersin sınırlayıcı ölçümü. İşaretlenmemiş bir uç nokta güvenli değildir ve güvensiz de değildir; hangisi olduğu, kaynağı okuyarak değil, kabın hangi varsayılanla kurulduğunu bilerek anlaşılır. Bu, dersin en önemli gözlemi: iki uç nokta arasındaki farkı “açık” ile “kapalı” gibi sabit bir sıfatla anmak yanıltıcı, çünkü sıfat kaynağa değil kurulum kararına ait.

Bu karar Uclar sınıfını yazan tarafa da ait değil; Bekci’yi kim kuruyorsa varsayılan onun elinde. Çok sayıda uç noktanın bulunduğu bir sınıfta yetki açıklaması unutulan tek bir yöntem, varsayılan açık bir kurulumda sessizce erişilebilir kalır — kaynakta hiçbir hata, hiçbir uyarı yok, çünkü unutulan bir işaret zaten hiçbir iz bırakmaz. Varsayılan kapalı bir kurulumda aynı unutkanlık tam tersi yönde çalışır: işaretlenmemiş her yöntem erişilmez kalır, ve eksikliği ancak çağıran tarafın “beklenmedik biçimde engellendi” gözlemiyle fark edilir. İki yön de aynı boşluğu dolduruyor, ama doldurduğu sonuç taban tabana zıt; hangi yönün seçildiği kabı kuran satırda bir kez yazılıyor ve bütün işaretlenmemiş yüzeyi aynı anda kapsıyor.

Varsayılanın yönü kaynakta görünmüyorsa, açıklama onu bastırabilir mi? surum yönteminin üzerindeki @Yetki(rol = "herkes") tam bunu deniyor: özel bir rol adı değil, bir açık kapı işareti.

// AcikcaBelirtilmis.java — herkese-acik isareti tasiyan bir uc nokta, kabin varsayilani kapali olsa bile aciklamadan geciyor
public class AcikcaBelirtilmis {
    public static void main(String[] args) throws Exception {
        Bekci kapaliBekci = new Bekci(new Uclar(), false);
        Bekci.gozle("surum, kapali-kurulumda", "aciklama", kapaliBekci.cagir("/surum", "misafir"));
        Bekci.gozle("durum, kapali-kurulumda", "varsayilan", kapaliBekci.cagir("/durum", "misafir"));
    }
}
surum, kapali-kurulumda                  aciklama   : surum-3
durum, kapali-kurulumda                  varsayilan : engellendi

Aynı kapaliBekci nesnesi üzerinde iki çağrı: surum açıklamayla herkese açık ilan edildiği için varsayılanı bastırıp geçiyor; durum hiçbir işaret taşımadığı için aynı kabın kapalı varsayılanına düşüyor. Açıklama varsa, varsayılan hiç devreye girmiyor — sıra ancak açıklama yoksa varsayılana geliyor. Bu, iki kaynağın öncelik sırasını gösteriyor: önce açıklama okunuyor, o yoksa varsayılana dönülüyor; kaynakta yazılı bir kural varsayılanın yönünden bağımsız olarak kazanıyor. Bu öncelik sırası da kaynakta değil izinVer yönteminin kendi gövdesinde duruyor — Bekci’yi yazan taraf hangi kaynağın önce sorulacağını baştan kararlaştırmış.

Elle Yazılan Yetki Denetimi

Üçüncü kaynak, önceki ikisinden ayrı bir sınıfta duruyor: ElleYetkili, filtre zincirine hiç girmeyen, @UcNokta ya da @Yetki taşımayan sıradan bir yöntem. Kararı burada nesne kabı değil, yöntemin kendi gövdesindeki bir denetim ifadesi veriyor.

// ElleYetkili.java — yetki karari nesne kabi ya da aciklama uzerinden degil, dogrudan kaynaktaki bir denetim ifadesinden geliyor (yardimci kaynak, main yok)
class ElleYetkili {
    String hassasIslem(String cagiranRolu) {
        if (!"yonetici".equals(cagiranRolu)) throw new SecurityException("yetkisiz erisim");
        return "hassas-veri";
    }

    String dene(String cagiranRolu) {
        try { return hassasIslem(cagiranRolu); }
        catch (SecurityException e) { return e.getClass().getSimpleName(); }
    }
}
// ElleKontrol.java — ayni iki rolle cagrildiginda, kararin kaynaktaki bir kosuldan geldigini gosteriyor
public class ElleKontrol {
    public static void main(String[] args) {
        ElleYetkili elle = new ElleYetkili();
        Bekci.gozle("hassasIslem, cagiran yonetici", "cagri", elle.dene("yonetici"));
        Bekci.gozle("hassasIslem, cagiran calisan", "cagri", elle.dene("calisan"));
    }
}
hassasIslem, cagiran yonetici            cagri      : hassas-veri
hassasIslem, cagiran calisan             cagri      : SecurityException

Sonuç FiltreKarari dersindekiyle aynı görünüyor — yönetici geçiyor, çalışan reddediliyor — ama kaynağı farklı. GT5. Elle yazılmış bir denetim ifadesi kararı doğrudan kaynaktan verir; ne bir açıklama ne nesne kabı araya girer, karar hassasIslem yönteminin ilk satırında duran karşılaştırmadan gelir. Bu üçüncü yol, Bekci’nin hiç yönetmediği bir sınıfta yaşıyor; ElleYetkili nesnesi Bekci’ye hiç kaydolmadı, dolayısıyla ne yetki açıklaması ne varsayılan yön ona uygulanabilir — bir önceki konunun kapanış dersindeki gözlemle aynı sınır burada da geçerli: kabın dışında kalan nesne, kabın sunduğu hiçbir düzeneği almaz.

Üç dersin de gösterdiği üç ayrı kaynak burada yan yana duruyor:

Kaynak Kararı veren yer Bu derste örneği
açıklama @Yetki işareti, Bekci tarafından okunur panel, surum
varsayılan Bekci kurulurken verilen varsayilanAcikMi durum
çağrı yöntemin kendi gövdesindeki denetim ifadesi hassasIslem

Aynı “yönetici mi değil mi” sorusu üç ayrı yerden üç ayrı biçimde yanıtlanıyor, ve kaynağı yalnızca okuyan biri — açıklamaları görse bile — hangi yanıtın hangi davranışı ürettiğini bilmeden yola çıkıyor. durum özelinde bu bilgisizlik daha da keskin: orada okunacak hiçbir işaret yok, karar tümüyle kabın kuruluş anına ait. Bu üç kaynağın hiçbiri “doğru” ya da “yanlış” değil; her biri farklı bir yerde tutuluyor ve kaynağı okuyan kişinin hangi yerlere bakması gerektiğini önceden bilmesi gerekiyor — kurs boyunca kurulan ölçüm ekseni tam olarak bu bilme ihtiyacını sayılabilir kılmak için var.

Üç kaynağın ayrımı bir de büyüklükle ilgili: açıklama ve varsayılan bütün bir sınıfı ya da bütün bir kabı tek bir kararla kapsıyor, elle yazılan denetim ise yalnız yazıldığı yöntemi. hassasIslem gibi on ayrı yöntem olsaydı, aynı karşılaştırma on kez tekrarlanırdı; işaret tabanlı yaklaşım bu tekrarı ortadan kaldırıyor ama karşılığında kararı kaynaktan kaba taşıyor. Bu ders çağıranın kimliğini zaten çözülmüş bir rol dizesi olarak aldı — "yonetici", "calisan", "misafir" — ve bu dizenin nereden geldiğini hiç sormadı.

Özet

  • Filtre zinciri, yetki açıklaması olan bir uç noktada kararı işaretten okur ve çağıranın rolüyle karşılaştırır; bu davranışın kaynağı açıklamadır.
  • Yetki açıklaması olmayan bir uç noktada karar kabın kendi varsayılanından gelir; kaynak metni bu davranışı hiç göstermez.
  • Aynı kaynak, yeniden derlenmeden, yalnız kabın kurulması sırasında verilen bir parametreyle iki farklı güvenlik duruşu üretebilir — sınırlayıcı ölçüm budur.
  • Açıklama varsa varsayılan hiç devreye girmez; öncelik sırası önce açıklama, sonra varsayılandır.
  • Elle yazılmış bir denetim ifadesi kararı doğrudan kaynaktan verir; bu yöntem kaba hiç kaydolmadığından ne açıklama ne varsayılan yön ona uygulanır.

Sonraki Adım

Bu ders çağıranın rolünü hazır bir dize olarak aldı — kim olduğu zaten bilinen bir girdiydi. Gerçek bir çağıran bu bilgiyi bir yerden taşımak zorunda, ve bu kurs sunucu tarafında bir oturum tutmuyor. Sıradaki ders bu rolün ve kimliğin sunucuda saklanan bir durumdan değil, çağıranın her istekte yanında getirdiği bir belirteçten nasıl geldiğini modelliyor.

İ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