Yazılımın ilk 250 günü - Part 17

12 dk okuma

161. Gün

Single sign on konusunda izlemem gereken adımları daha çok öğrendim. Detaylı şekilde her kısmını düşünmüş olmasam da basitçe bir otorizasyon ve doğrulamanın nasıl yapılması gerektiği üzerine bir şemayı takip edip kodlamaya çalışıyorum. Bugün yaşadığım problem günün sonunda da çözemedim açıkçası. Bir sunucu diğer sunucuya post metodu ile istek gönderip cevabı da almak istediğinde (axios kullanarak), cevabını normal ve sıradan değişkenleri alırken problem çıkmadan alabiliyor fakat session bilgisini alamıyor. Oysa ki session bilgisi o sunucudaki kalan diğer her yerden ulaşılabiliyor. Hatta get metodu ile o sunucudan veri alırken de session verisine basitçe erişiliyor. Yarın sabah tekrar odaklanarak problemin ana kaynağını bulup çözmeye çalışacağım ya da alternatif olarak get metodu ile çözümleyeceğim. Ek olarak, geçişleri express’in sağladığı redirect metodundan client side’da normal şekilde farklı bir url’ye aktarımı sağladım. Her kullandığım yerde. Ona rağmen devam etmekte.

162. Gün

Dün karşılaştığım problemi sizin ifadenizle hackish bi şekilde gidermiştim. Fakat sonrasında yine aynı problemle karşılaşınca sorunun tam olarak neden kaynaklandığını anlamaya çalıştım. Aynı domain adresinden gelen post isteği üzerinde işlem yaparken session’a veri ekleyebiliyordum. Aynı domain adresinden gelen get isteğinde de problem yoktu. Fakat farklı bir domain’den gelen get ya da post isteği ile işlemler yapabilsem de session’a veri kaydedemiyordum. Eğer işlemler yapmama izin veriyorsa CORS’a izin veriyor diye düşündüm. Ama eğer session’a veri ekleyemiyorsam CSRF’e karşı önlem olduğu için istediğim sonucu elde edemediğimi düşündüm. Bu yüzden yarın sabah ona bakacağım.

Neredeyim?

If(kullanıcı is not authenticated) Domain A-> Domain B; //Henüz bu kısımdaki işlemler kodlanmadı

//Domain B, Domain A’dan gelen parametreleri de kullanarak önce kullanıcıdan giriş bilgilerini alıp teyit eder. Eğer doğru ise Domain A’ya otorizasyon kodu gönderir. Domain A ise karşılığında cliend id, client secret bilgileri ile auth code’u geri gönderir. Burada Domain B gerekli token’ları oluşturur. Neden direkt gerekli token’ları (id token, access token, refresh token gibi) göndermedi? Çünkü kullancının iznine bağlı olarak authorization yapılacak bir kısım varsa, kullancının sitenin istediği scope’ları bilmesi sağlanır. Bunun şu anki sistemde olması gerekmiyor ama gördüğüm örneklerde var diye bu şekilde ekledim (silinebilir ya da geliştirilebilir). Sonrasında, Domain A id token’ı kullanıcı bilgilerini görmek için kullanır(id token eğer Domain A authorization için scope’ta bunu belirttiyse gönderilir (openid’de kullanılan şekli ile)). Access token sadece authorization bulunan alanlara erişebilmek için kullanılır (Örneğin farklı kaynak sunuculardan veri almak istediğimizde yetkilerimizn ne olduğunu o kaynaklara erişmek istediğimizde görebiliriz. Orjinalde access token’ı Domain A okuyup anlamamalı. Bunu sağlamak için hs256 gibi simetrik bir algoritma kullanmak yerine rs256 gibi asimetrik bir algoritma tercih edilebilir. Edilmeyedebilir aslında, tercih meselesi anladığım kadarı ile.). Bugün son olarak token’ları oluşturdum JWT token olarak ve client secret ile hem Domain A hem de Domain B’de okunabilmekte. Sorun Domain B’den Domain A’ya token’ları post ile gönderdiğimde session’ına yazamamam. Tahmin ettiğim üzere CSRF ile ilgili bir sorun olduğu için Bu akşam bu konu üzerine biraz okuma yaptım. Buradaki middleware ile sorunu çözebilecek miyim bilmiyorum fakat yarın ilk bu duruma bakacağım. Bu yazıdaki tavsiyelere ve dikkat edilmesi gereken uyarılara da dikkat etmeye çalışacağım. En azından aklımda yer edinmesi gerekliymiş gibi geldi.


Sonrasında yapmam gerekenler: Şu durumdaki sorun benim hep session’I tercih etmiş olmayı istemem. Aslında cookie’de tutmam gerekliydi bazı bilgileri (kullanıcının giriş yapmış olup olmadığı ile ilgili bilgi gibi) çünkü kullanıcı tarayıcı kapatınca tamamen session’ın silinmesi söz konusu. Anladığım kadarı ile bir parametreyi değiştirerek bunu engellemek de mümkünmüş fakat şu an net hatırlayamadım. Gerekirse çereze de ilgili verileri kaydederim ya da session ayarlarını değiştirebilirim.

Genel olarak sonrasında yapmam gerekenler: Kullanıcı farklı bir domain adresine girince (benim ilgilendiğim,sahip olduğum domain üzerinde), öncelikle çerez’e ya da session’a bakılır. Eğer gerekli kullanıcı bilgisi yoksa Domain B’ye yani auth server’a sorar kullanıcı giriş yapmış mı diye. Eğer yapmadıysa o şekilde işlemlerine kaldığı yerden devam eder. Kullanıcıyı rahatsız etmez. (Kullanıcı farklı bir domainim’de giriş yapmışsa auth server’da kullanıcı bilgisi session’ında ya da çerezinde yer alacaktı. Dolayısıyla şu anki sitede de giriş sağlanacaktı ve gerekli bilgiler bu domain adresine verilecekti).

Kısacası yapmam gereken kısımlar hâlâ var SSO konusunda. Ama sorunlara, yapmam gerekenlere daha iyi hakimim diyebilirim. Sadece takıldığım konularda kullandığım araçları daha verimli şekilde kullanmalıyım diye düşünüyorum.

163. Gün

Bugün üzerine çalıştığım kurguyu tamamlayamadım. Ya benim kurgumda bir problem var ya da teknik problemlerini aşamıyorum her gördüğüm kaynaktaki olası çözümleri denesem de. Bence kurgumda bir hata olduğu için istediğim sonucu elde edemiyorum. Tekrar deneyeceğim. Açıkçası istediklerimi yapamayınca üzülsem de ağlasam da denemeye, öğrenmeye, ders çıkarmaya devam edeceğim.

164. Gün

Bu hafta istediğim yere gelemedim. Ama bu görevimde başarısız olacağım anlamına gelmiyor. Bilakis yapacağım. Yarın da o yüzden çalışacağım diye düşünüyorum çünkü yapmak istiyorum. Sizin bana gösterdiğiniz kodları kendim de yazdım. Sorunsuz şekilde çalışıyor o kısım. Yarın kendi kurgumu onun üstüne güzel bir şekilde yazıp, yapbozun bir parçasını ekler gibi eklemek istiyorum. 95$ ödenir fakat gerçekten hakkınızı nasıl öderim şu an hiç bilmiyorum. Şirkette işe başlamadan önce bir arkadaşımla konuşuyordum. Kendisi de PHP, wordpress, vs. ile ilgilenen, hatta OOP, MVC, vs. denince aşırı zor şeylermiş (Yunan tanrıları tarafından alınan kararlar sonucu oluşan mistik ve ilahi şeylermiş) gibi anlatırdı fakat kendisi de neredeyse hiç bilmiyordu. Bugün onunla konuşunca o zamanlar benden biraz daha konu ile ilgili bir insan ile şu anki hâlim arasındaki farkı öyle iyi anlıyorum ki. Her zaman kendimi yeriyorum, hiçbir şey bilmediğimi düşünüyorum ne kadar çok şey ile uğraşsam da. Fakat konu ile alakalı olmayan ya da olan biri ile konuşunca aradaki farkı çok iyi hissediyorum. Sadece sizinle konuşurken zorlanıyorum. İyi ki de zorlanıyorum. Dün akşam Linkedln’de bir gönderi görmüştüm. GPA’in, tecrüben, vs. (elbette gerekliler bazı kriterler için) unutulur fakat insanlarla bağın, ilişkin, yaklaşımın kalır ve hatırlanır tarzı bir yazıydı. Sanırım sadece iş hayatında değil hayatın kendisinde de daha iyi dikkat etmeye çalışacağım buna. İnsana değer vermeyi, dinlemeyi, anlamayı, sevmeyi, merhameti ve tevazuyu daha da ilerletmek istiyorum. Böyle “boş”ta yapabiliyorum çünkü sizinle olan bağımdan dolayı kendimi bir derece rahat hissediyorum.

165. Gün

İlerliyorum. Kullanıcı SSO sunucu kullanılarak gayet normal bir şekilde giriş yapabiliyordu. SSO’dan sadece gerekli kullanıcı bilgileri, ilgili client sunucu(lara) veriliyor. SSO sunucusu ile iletişimlerde sadece bir kez idToken oluşturulup clientSecret paylaşılıyor. Onun dışında güvenlik tehdidi olabilecek bir kullanıcı bilgisi direkt olarak sunucular arasında paylaşılmıyor. Güvenlik sorunları sonrasında düzeltilebilir. Daha büyük bir problemim var. Asıl SSO’nun çalışma mekanizmasında bir problem bu fakat çözeceğim. Farklı bir siteden giriş yapınca, o site SSO’ya yönlendirilip SSO’da o kullanıcı daha giriş yapmış mı diye kontrol edilir. Ben burda hep SSO’nun çerezinde idtoken’I tutarak ilk kontrolü buradan yaparım diye düşündüm. Çünkü eğer SSO’nun çerezinde idToken veya herhangi benzeri bir tanımlayıcı veri yoksa, kullanıcının giriş yapmış olduğunu nasıl anlayabilirdim? SSO’nun kullandığı veritabanında bu oturum açıp açmama bilgisini tutarak olabilirdi. Ben hem SSO çerezinde hem de veritabanında tutmayı makul gördüm. Kullanıcının tarayıcısında giriş yapıp yapmadığı bilgisini tutmak daha sağlıklı olur diye düşündüm. Fakat bunu manipüle edebilecek kötü niyetlere karşı da veritabanında bu bilgiyi tutarak karşılaştırma yapabilirdim. Belki karmaşık ve yanlış düşünüyor olabilirim. Sadece Ip adresine bakılarak da yapılabilir. Ya da sadece çerez veya veritabanındaki bilgiye bakılarak da yapılabilir. En büyük sorun şu an farklı client sunuculardan oturumu control etmek ve ona göre o sunucuların da client tarafında çerezlerini kaydetmek. Bugünün en tatlı yanı client secret hep değişen şekilde kaydetmem oldu. Her yeni oturum açlımında client secret değişmekte ve güvenliğe de faydalı olmakta (Id token’I açmanın tek yolu kendisini bilmek. Tüm sitelerde de tek bir idtoken ve tek bir client secret olduğu için bence çok ufak ve güzel bir ayrıntı.)

Bugün başlangıçta sistemli olarak düşüncelerimi koda yansıtsam da sonra ipin ucu kaçıp domuz düğümüne dönmüş gibi oldu.

Yarın ne yapacağım?

SSO’nun çerezinde idToken’I tutmak ne kadar doğru onu düşünüyorum. Hiç çerezinde idtoken eklenmeyen bir site giriş yapılıp yapılmadığını anlamak için SSO’ya gider. SSO ise kendi çerezinde idToken olup olmadığına bakar ve database yada sürekli verinin tutulduğu herhangi bir yerden idToken’I control edip sonrasında idToken’I ve client secret’I o sunucuya tedarik eder. En önemli husus, bu durumun taklit edilmesine yönelik iyi bir koruma sağlamaktır (İzin verilen domain’lerden gelip gelmediği kontrol edilir). Başka problemli bir yönü yoktur.

Kısacası yarın asıl SSO kısmını tamamlamayı planıyorum kaba olarak. Başarabilirsem ince işçiliğine gireceğim.

166. Gün

Bir siteden çıkış yapan kullanıcı tekrar giriş yapmak istediğinde tıpkı Google’da olduğu gibi “selam GayeSu, bu sen misin?” dedikten sonra eğer o kişi olduğunu teyit ederse onun şifresini almak ve doğrulayıp tekrar giriş yapmasını sağlamak istiyorum. Ayrıca o eski giriş yapan kişi değilse de normal kullanıcı ismi ve şifrenin olduğu standart formu vermek istiyorum. Onu yapmaya çalışırken yarım kaldı çalışmam. Tüm sitelerden çıkma özelliğini son olarak eklemeyi düşünüyorum. Böyle bir durumda, o sso’yu kullanan sunuculara bir middleware eklemem gerekecek, hepsinden çıkış yapmış mı kontrolünü sağlamak ve görebilmek için.

Yarın kaldığım yerden devam edeceğim. Daha sistemli gidiyorum. Kod uzamaktan çok evriliyor ve değişiyor şu birkaç günde. Yarın olmasa da sonraki gün SSO genel manada ortaya çıkar diye düşünüyorum. İlk defa Node.js ile bu kadar çok çalıştım, iyi ki çalıştım.

Bugün farklı bir bilgi öğrendim konu ile alakasız olarak. "res.sendfile()" diyerek bir dosyayı tarayıcıya sağlarken stream bir veri gönderimi sağlanıyormuş. Bu ne demek? Normalde ben o dosyayı önce "fs.readfile()" diyerek sunucu hafızasını tüketiyorum fakat diğer şekilde dosyayı küçük veri paketleri halinde tarayıcıya sağlıyormuşum. Bu da performans açısından çok daha sağlıklı oluyormuş. Veriyi hafızaya kaydet. Tarayıcıya gönder. Garbage collector temizlik işlemini yapsın gibi işlemlerden kurtarıyor bir nevi.

167. Gün

SSO ile ilgili görevin ilk kısmında aklıma gelen olasılıkların hepsini denedim. Sadece güvenlik açıkları kesinlikle var. Farklı büyük bir hata varsa ve ben farketmemişsem eğer mantıksal işleyiş açısından, düzeltebileceğimi düşünüyorum çok zorlanmadan. SSO’da tüm kullanıcı girişi işlemleri SSO sunucusuna dayalı. Bu sunucunun hizmet verdiği client web siteleri için en önemli konu, çerezlerinde tuttukları idToken. Tüm kullanıcı bilgisi şifrelenmiş şekilde idToken içerisinde yer almakta. idToken’I okumanın tek yolu client sunucuların ortak olarak kullandığı veritabanında tutulan client secret isimli veri. Bu veri sabit değil. Her oturum açılışında o kullanıcıya özel olarak 2 ya da 3 tane kriptografik şifreleme işlemi (Önce client id ve auth code bu şekilde oluşturulduktan sonra, o veriler client secret’in oluşturulmasında kullanılıyor. Tahmin etmek çok zordur diye tahmin ediyorum) sonrasında oluşturuluyor. Kullanıcı eğer tek bir client web sitesinden çıkış yaparsa sadece o sitedeki oturumu kapatılıyor. Diğer sitelerde oturum aynı şekilde kalıyor. Eğer kullanıcı hepsinde oturumu kapatmak isterse tüm hepsinde oturum SSO aracılığı ile kapatılıyor (Client sunucular bu durum için küçük bir middleware ile SSO'ya tüm oturumlar kapatılmış mı diye sorguda bulunuyor.). Eğer sadece bir websitesinde oturum açılmışsa, diğer websiteleri de bu oturuma erişebiliyor. Yani SSO anlamına kavuşuyor. İkinci bir client olmadığı için tam olarak test edemedim fakat şu an istediğim gibi çalışıyor.

SSO sunucusu veritabanında kullanıcı bilgileri ile idToken’I tutmakta iken, client sunucu veritabanında SSO’nun sunduğu veriye dayanarak kendi kullanıcı tablosunu oluşturuyor. Authentication ile ilgili sadece clientSecret’I her kullanıcı için ayrı olarak tutmakta. Kullanıcı bilgileri hiçbir zaman direkt olarak transfer edilmiyor ve tüm iletişim idtoken üzerinden işliyor olması gerektiği gibi. Client secret’I client sunucu oluşturup sadece ilk oturum açma işleminde SSO’ya aktarıp idToken’ın oluşturulmasını sağlıyor.

Node.js, express, ve genel olarak node.js ortamında çalışmaya bu verdiğiniz proje ile adapte olabildim. Yarın dediğiniz üzere socket konusuna bakacağım. Önce yapmam gerekenleri kendimce listeleyip, nasıl yapabileceğim üzerine ufak çapta eskizler hayal edip hedeflerimi gerçekleştirmeye çalışacağım. O kadar OOP ve tasarım deseni dedikten sonra şu aşamada hiçbirini kullanmamam üzse de, o aşamaya da geleceğimi düşünüyorum. Bir anda (Tanrı 6 günde yaratmış, bilime göre 14 milyar yıl?) insan nesnesini yekpare yaratmaktan ziyade, ona evrilerek ilerleyen bir yapı kurmak sanırım yaptığım ve yapmaya çalıştığım şey. Dolayısıyla arzu edilen desenler de açığa çıkacaktır. OOP ve SOLID’e uygun bir yapı ortaya çıkar diye düşünüyorum ileriki aşamalarda.

168. Gün

Bugün idToken mantığını çerezden session’a taşıdım. Taşırken kodun birçok kısmında değişiklikler yapıp ekstra iyileştirmeler de yaptım. Tüm gün bunlarla geçti açıkçası. Şu an yine istediğim gibi çalışmakta. Bugün yaptığım değişikliğin sebebi, bazı verileri nerede tutmamam gerektiği üzerineydi. Çerezde birtakım hassas veri tutmanın yanlış olduğunu “yaparak” öğrendim ve düzelttim. Bir daha böyle bir hata yapmam diye düşünüyorum.

Yarın artık farklı bir socket.io ile yapacaklarım üzerine yoğunlaşacağımı düşünüyorum.

169. Gün

Socket.io ile ilk karşılaştığım zamanda olduğu gibi örnek kodu kopyalayıp üzerinden gitmeyi düşündüm günün ilk kısmında. Sonrasında kendi sistemimi tasarlayıp ona göre socket’i kullanarak yazmalıyım dedim. SSO yu kullanarak giriş yapan kullanıcıya tıpkı skype/ve diğer benzeri uygulamalardaki gibi bir front end sunulacak. Yarın kabataslak html ve css ile temel bir görünüm vereceğim. Skype’ın bir benzerini html ve css kullanarak en basit düzeyde yazıp sonrasında socket kullanarak veri alışverişini sağlamaya çalışacağım client ve server arasında. Açıkçası bunu sorunsuz şekilde yapabilirsem geriye sadece bu yazılan kodu electron kullanarak implement etmek kalıyor. Bir de text dosyası yerine veritabanı kullanmak kalıyor. Sonraında orm ya da odm de kullanılabilir gerçi. Routing’in çoğunluğunu login kısmı oluşturdu. Uygulama aslında neredeyse single page application gibi olacak düşününce (tam olarak değil tabii ki, authentication’da farklı route’lar da kullandım).

Çok zor bir şey yok gerçekten fakat hala çok yavaşım. Hızlanmaya çalışıyorum. Örneğin bugünün çoğunluğu dosya yapılarını düzeltmekle geçti. Aslında pek bir şey de yapmadım şimdi düşününce fakat yine de zamanımı aldı. Authentication kısmını farklı bir klasöre aldım. Sonrasında socket ile ilgili işlemleri nerede yapacağıma dair ana javascript dosyasında da düzenlemeler yaptım. Bu ayırma sırasında middleware kullanırken biraz sorunlar yaşayıp istediğim hale getirdim. Zamanımı alan bu ufak sorunlardı fakat size de sormak istemedim, kendim çözmek, bulmak, öğrenmek istedim. Zor da olsa ayakta durabilen bir bebeğin ebeveyninin yardımını istemeden kendince yürümeye çalışması ve defalarca kez düşse de normal şekilde yürümeye başlaması gibi sanki. Koşmak dileği ile tabii ki.

Büyük konuşmamalıyım fakat haftaya soket kısmı çok rahat biter diye düşünüyorum. Sonraki hafta da electron’u kullanmayı ve orada bu kod yapısını (Html ve Css ile client’ta yaptıklarımı electron’a) uygularım diye düşünüyorum. Bence güzel ve güneşli günler yakın.

170. Gün

Bugün sadece html/css/javascript ile çalıştım. Çalıştığım kısım henüz bitmedi fakat yarısı tamamlandı. İlk defa css’te değişken kullandım bugün. Kullanmış olmak için kullanmadım. Karanlık/aydınlık teması yapmak istemiştim ve bunun için de css değişkenleri kullanmak oldukça verimliymiş.

Ek olarak, html kullanırken her zaman resmin genelini düşünerek hareket etmeye çalışıyorum. Gelecek verileri ve ilişkilerini bu yazdığım html kodları ile nasıl yansıtabilirim diye düşünerek yazmaya çalışıyorum. En son html/css kullandığım zaman ile şimdi arasındaki farkı hissediyorum.