Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

.NET WebAPI – Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWT

Merhaba,

Bu içeriğimizde, Amazon Cognito ile .NET WebAPI’ın güvenliğini sağlama konusunda kapsamlı bir inceleme çalışması gerçekleştiriyor olacağız. Odak noktamız, OAUth ve Amazon Cognito eşliğinde Serverless Authentication sistemi oluşturabilme üzerine olacaktır. Bu içeriğin sonunda .NET WebAPI’larınızın güvence altına almak için Amazon Cognito’yu nasıl uygulayacağınızı tam teferruatlı anlamış olacaksınız kanaatindeyim. O halde vakit kaybetmeksizin buyurun başlayalım…

Amazon Cognito Nedir?

Geliştirilen uygulamanın ölçeği ne olursa olsun kimlik doğrulama her daim önem arz edecek olan kritik ihtiyaçlardan birisidir. Bu ihtiyacı ister kendi özel oluşturduğunuz kimlik doğrulama stratejisi ile isterseniz de third party provider’lar ile sağlayabilir ve kullanabilirsiniz. Ya da isterseniz de AWS tarafından sağlanan kullanıcı kimlik ve yönetim hizmeti olan Amazon Cognito’yu da tercih edebilirsiniz.

Amazon Cognito; kimlik doğrulama, kullanıcı yönetimi ve veri senkronizasyonu gibi özellikleri sağlayarak uygulamaların geliştirme süreçlerinde pratikleştirici bir nitelik sağlamaktadır.

Amazon Cognito ile özellikle mobil ve web uygulamaları gibi farklı platformlarda kullanıcıların kimliklerini doğrulamak için OAuth 2.0, OpenID Connect veya SAML vs. gibi standart kimlik sağlayıcıları ile entegre olunabilmektedir. Böylece .NET geliştiricileri olarak kendi kimlik doğrulama sistemimizi OpenIddict veya IdentityServer4 gibi kütüphaneleri kullanarak geliştirmek yerine(ki bunlar hala geçerli yaklaşımlardır), Amazon Cognito servisiyle oldukça avantajlı ve efektif bir şekilde kurgulayabiliriz.

Böylece;

  • Amazon Cognito’nun sağlayacağı akıcı bir kullanıcı arayüzü üzerinden nispeten kolay bir kullanıcı yönetimi ve oturum işlemleri gerçekleştirilebilecek ve Facebook, Google vs. gibi harici identity provider’lar da basit ama etkili bir şekilde desteklenebilecektir.
  • Herhangi bir altyapı ihtiyacına dair endişeye gerek kalmaksızın; Amazon Cognito, istenilen sayıda kullanıcıya uyum sağlayacak şekilde ölçeklenebilecektir.
  • Özelleştirilmiş kimlik doğrulama sitemi tasarlarken, potansiyel hataların ve açıkların oluşma olasılığı oldukça düşük olacak ve böylece birinci sınıf güvenlik sağlanacaktır.
  • Diğer AWS servisleriyle olan entegrasyon kolayca yürütülebilecektir.
  • Ve son olarak tüm bu özellikler aylık 50.000 aktif kullanıcıya ve external identity provider açısından da 50 kullanıcının oturum açmasına kadar ücretsiz olarak kullanılabilecektir. Ha eğer ki bu sınırların aşılması gerekiyorsa bunun da oldukça makul fiyat politikasıyla gerçekleştirilmesi mümkündür. https://aws.amazon.com/tr/cognito/pricing/

Ne İnşa Edeceğiz?

Amazon Cognito’yu kullanarak serverless bir authentication sistemi tarafından güvenliği sağlanan Web API geliştireceğiz. Bu API’daki authentication, Amazon Cognito User Pool tarafından oluşturulan JWT’ye dayanacaktır.

Bunun için ilk olarak Cognito’da client credentials ve password flow ayarlamalarını gerçekleştirecek ve daha sonra da bu akışların bize belirli bir kullanıcı için token üretebilme yeteneğini test edeceğiz. Bu işlem tamamlandığında, Amazon Cognito tarafından güvenli hale getirilen API’ı oluşturacak ve bu API’ın her iki akıştan gelen token’ları alabildiğini ve güvenli bir API endpoint’ine yapılan request’leri doğrulayabildiğini kontrol edeceğiz.

Client Credential Flow & Password Grant Flow

Client Credential Flow’da client(yani geliştireceğimiz Web API), access token karşılığında Cognito’ya client id ve secret değerlerini iletecek ve herhangi bir kullanıcı onayına ihtiyaç duymaksızın client yetkilendirilecektir.

Password Grant Flow ise kullanıcının kaynaklarına erişmek için bir server authentication yapılması gerekmektedir. Dolayısıyla bu noktada kullanıcı adı ve şifre gibi kullanıcı bilgilerinin gönderilmesi elzemdir.

Amazon Cognito User Pool Oluşturma

Şimdi ilk olarak Amazon Cognito User Pool oluşturmaya odaklanalım. Bunun için AWS’ye giriş yapalım ve AWS Console üzerinden Cognito’yu aratalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTAşağıda görüldüğü üzere Cognito user pool sekmesini seçiyor ve oturum açma seçeneği için de kullanıcı adı ve şifreyi seçiyoruz. Turuncu kısımdaki ‘Federated identity providers’ seçeneği ise Google, Facebook vs. gibi third party identity provider’ları ile ilgilidir. .NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTDevamında ise Cognito’nun varsayılan şifre politikasını seçiyoruz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWT2. adımda sayfayı biraz daha aşağı indirdiğimizde Multi-factor authentication(çok faktörlü kimlik doğrulama) davranışıyla ilgili yapılandırmayı göreceğiz. Her ne kadar kaynakları korumanın güvenli bir yolu olsa da bizler bu içeriğimizde multi-factor authentication’a dair herhangi bir çalışma yapmayacağız..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTDevamında ise 3. adımı varsayılan ayarlarında bırakarak direkt geçebiliriz. Amma velakin 4. adımda onay mailene dair yapılandırmada bulunabilmek için Cognito’nun varsayılan e-posta adresinden istifade edebiliriz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTArdından oluşturduğumuz bu user pool’a bir isim verelim. Ayrıca Use the Cognito Hosted UI seçeneğini etkinleştirerek görseldeki gibi bir Cognito domain alalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTVe son olarak 5. adımda sayfanın az aşağısına gelirsek eğer user pool application client yapılandırmasında bulunacağız. Burada token oluşturması için client credential grant type flow’u yönetmekten sorumlu bir client oluşturacağız..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTYukarıdaki ekran görüntüsünde olduğu gibi client credential flow açısından oldukça önemli olan Generate a client secret‘ın seçili olduğundan emin olmanızda fayda var. Ayrıca callback url olarak şimdilik sahte bir değeri girelim ve user pool’u oluşturalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWT

Client Credentials Flow: Kurulum ve Test

Şimdi bu oluşturduğumuz user pool client’ında client credentials flow’u uygulayacağız. Zaten güvenlik nedenleriyle aynı user pool client’ında birden fazla flow uygulanamamaktadır. Bu nedenle içeriğimizin sonraki satırlarında password grant flow’u uygularken de bunun için yeni bir client oluşturuyor olacağız.

Client credential flow’un temel fikri; client’ın kullanıcı kimlik bilgileri yerine, client id ve client secret gibi kendisine ait kimlik bilgileri eşliğinde Amazon Cognito’dan authentication yapması üzerine kuruludur. Bu akış genellikle protected edilmiş resource’lara erişimi sağlayabilmek için sadece client’ın yetkilendirilmesinin yeterli olduğu senaryolarda tercih edilmektedir. Bizlerde bu senaryoya benzer bir çalışma yapacağımızdan dolayı erişim açısından örneklendirmeyi sağlayabilmek için bir resource server’a ihtiyacımız söz konusudur.

Bunun için yukarıdaki satırlarda oluşturduğumuz ‘cognito-example’ isimli user pool’a girelim ve aşağıdaki ekran görüntüsünde olduğu gibi ‘App integration’ sekmesi üzerinden ‘Resource servers’ alanında ‘Create resource server’ butonuna tıklayalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTResource server’ı aşağıdaki gibi oluşturalım. Tabi burada dikkat edilmesi gereken nokta şudur ki, oluşturulacak bu resource server’a bir scope eklendiğinden emin olunması gerekmektedir. Görselde de görüldüğü üzere ben oluşturulan resouce server ismiyle birebir aynı olan değeri ekliyorum. Bu değere yazının sonraki seyrinde JWT oluştururken ihtiyacımız olduğunu göreceksiniz….NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTVe ardından resource server’ın oluşturulduğunu gözlemleyelim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTBu işlemden sonra yine user pool üzerinden önceki satırlarda oluşturmuş olduğumuz ‘example-client’ isimli application client’a gidelim ve ‘Hosted UI’ bölümüne ilerleyelim. Bunun için aşağıdaki görselde olduğu gibi ‘App integration’ sekmesi üzerinden ‘App clients and analytics’ başlığı altından erişim gösterilebilmektedir..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTBu adımda aşağıdaki görselde olduğu gibi ‘Identity providers’ın ‘Cognito user pool’ ve ‘OAuth 2.0 grant types’ın da ‘Client credentials’ olduğundan emin olunuz. Ayrıca, daha önce oluşturduğumuz scope’u da ‘Custom scopes’ kısmında seçtiğimize dikkatinizi çekerim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTEvet, credential flow için yapılması gereken tüm çalışmalar bunlardan ibaret. Artık oluşturduğumuz ‘example-client’ın detayına giderek client id ve client secret değerlerini görebilir ve istediğimiz yere depolayabiliriz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTŞimdi client credential flow’u kullanarak bir JWT token oluşturma testi gerçekleştirelim. Bunun için ben deniz Insomnia arayüzünü kullanacağım. Ha tabi ki de sizler isterseniz Postman ya da farklı bir araçlardan istifade edebilirsiniz.

JWT oluşturabilmek için aşağıdaki url’e verilen parametreler eşliğinde bir POST request’i göndermemiz yeterlidir.

https://{domain}.auth.{region}.amazoncognito.com/oauth2/token

Buradaki domain ve region bilgilerini peşinen elde etmek için oluşturulan user pool’un ‘App integration’ sekmesi altındaki ‘Domain’ başlığına göz atabilirsiniz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTVelhasıl isteği aşağıdaki parametreler eşliğinde gönderelim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTGörüldüğü üzere tarafımızca client credential flow kullanılarak yapılan istek, Amazon Cognito’da doğrulandı ve bir access token üreterek, elde etmemizi sağladı. Şimdi bu JWT değerini jwt.io‘da decode ederek incelersek eğer;.NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTiçerisinde client_id ve scope bilgileri eşliğinde dataların bulunduğu görmekteyiz.

İçeriğimizin bu noktasına kadar client credential flow’a odaklı çalışıp, test amaçlı bir doğrulama gerçekleştirmiş bulunuyoruz. Bir sonraki adımda password grant flow’a odaklanacak ve kullanıcı adı ile birlikte şifresini kullanacağımız çalışmaları gerçekleştireceğiz.

Password Grant Flow: Kurulum ve Test

Şimdi de password grant flow authentication için başka bir application client oluşturmamız gerekmektedir. Bunun için aşağıdaki ekran görüntüsünde olduğu gibi ‘cognito-example’ isminde oluşturduğumuz user pool üzerinden ‘App integration’ sekmesine gelelim, oradan da sayfanın biraz aşağısındaki ‘App client list’ kısmından ‘Create app client’ butonuna tıklayarak yeni client oluşturma sayfasına gelelim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTBu sefer de dikkat ederseniz ‘example-password-client’ adında bir client oluşturuyoruz. Burada dikkat edilmesi gereken nokta ise aşağıdaki görselde vurgulandığı gibi artık gerek duyulmayacağından dolayı bir secret key oluşturtmuyoruz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTSayfada hafif aşağı inersek eğer ‘Authentication flows’ kısmında ALLOW_USER_PASSWORD_AUTH değerini seçelim. Bunun dışında aşağıdaki ekran görüntüsünde olduğu gibi oluşturulacak token’a dair expiration değerlerini kendinize ya da iş kurallarınıza göre belirleyebilirsiniz. Biz varsayılan değerlere bağlı kalarak yola devam edelim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTDevamında ise sayfayı biraz daha aşağı indirerek ‘Hosted UI settings’ kısmına gelelim ve bir callback url belirleyelim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTTabi burada ‘Identity providers’ olarak ‘Cognito user pool’u seçtiğimizden ve ‘OAuth 2.0 grant types’ı da aşağıdaki gibi ‘Implicit grant’ seçtiğimizden emin olalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTVe nihai olarak client’ımızı oluşturalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTBu adımdan sonra artık bir kullanıcı oluşturmamız gerekecektir. Bunun için tekrardan oluşturduğumuz user pool’a gelelim ve ‘Users’ sekmesi üzerinden kullanıcı oluşturma işlemini aşağıdaki gibi gerçekleştirelim..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTGörüldüğü üzere ‘şuayip’ adında bir kullanıcı oluşturmuş bulunuyoruz.

Hazır lafı geçmişken buradan Şuayip abiye de selamlar olsun🤚🥸

Ha tabi burada girilen şifrenin geçici olduğunu da unutmamak lazım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTGörüldüğü üzere kullanıcı oluşturulmuş ve etkinleştirilmiştir. Lakin ‘Confirmation status’e göz atarsanız şifreyi değiştirmemiz gerektiğini söylemektedir. Bunun için AWS CLI’den aşağıdaki gibi istifade edebiliriz.

aws cognito-idp admin-set-user-password --user-pool-id "<user-pool-id>"  --username "<username>" --password "<permanent-password>" --permanent

Bizler misal olarak, bu talimatı aşağıdaki gibi kullanalım;

aws cognito-idp admin-set-user-password --user-pool-id "us-east-1_Vol2qyQFn"  --username "şuayip" --password "1q2w3E4'" --permanent
AWS CLI komutunu çalıştırabilmek için AWS Credentials ve profile bilgilerini bilgisayarınızda önceden ayarlamış olmanız gerekmektedir. Konuya dair .NET Uygulamaları İçin Detaylı AWS Credentials Konfigürasyonu başlıklı makalemi okumanızı tavsiye ederim.

Bu işlem tamamlandıktan sonra eklediğimiz kullanıcının onaylanmış olduğunu göreceksiniz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTŞimdi bu vaziyette testimizi gerçekleştirebiliriz.

Biliyorsunuz ki, password grant flow’da user credentials bilgilerinin sunucuya iletilmesi gerekmektedir. Bunun için de OAuth 2.0 protokolü kapsamında gerçekleşecek olan yetkilendirme işlemlerini destekleyecek header’lar eşliğinde request’te bulunmamız gerekmektedir. Haliyle https://cognito-idp.{region}.amazonaws.com/ adresine aşağıdaki ayarlarda bir POST isteğinde bulunulması gerekmektedir..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTYapılacak isteğin header’larına yukarıdaki görsel üzerinden göz atarsak eğer; ‘Content-Type’a karşılık AWS tarafından JSON formatına karşın belirlenmiş güvenli ve tutarlı bir standart olan application/x-amz-json-1.1 değerini veriyoruz. Böylece AWS Cognito Identity Provider API’ıyla kuracağımız iletişimde göndereceğimiz kullanıcı adı ve şifre gibi verilerin biçimini ifade etmiş oluyoruz.

‘X-Amz-Target’ başlığına karşılık ise AWSCognitoIdentityProviderService.InitiateAuth değerini veriyoruz. Böylece yapılacak request’in hangi AWS servisine gideceğini ifade etmiş oluyoruz. Bu header’lar eşliğinde request’in body’sini de aşağıdaki gibi ayarlayalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTBurada oluşturduğumuz client’ın id değeri eşliğinde gerekli olan tüm bilgileri verdikten sonra istekte bulunalım..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTVee görüldüğü üzere ‘AccessToken’, ‘IdToken’ ve ‘RefreshToken’lar oluşturulup, tarafımızca elde edilmiştir.

Şimdi içeriğimizin seyri açısından client credential flow ve password grant flow’u incelediğimize göre geriye, serverless authentication işlemini kullanarak tarafımızca oluşturulmuş olan bir Asp.NET Core Web API uygulamasının güvenliğini sağlamak kalmıştır.

Amazon Cognito İle Web API’ın Güvenliğini Sağlama

İlk olarak bir Asp.NET Core Web API projesi oluşturalım ve ardından ilgili projeye aşağıdaki kütüphaneleri yükleyelim.

.NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTGerekli paketleri yükledikten sonra uygulamanın yapılandırmasını aşağıdaki gibi gerçekleştirelim;

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCognitoIdentity();

builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        //                   https://cognito-idp.{region}.amazonaws.com/{user-pool-id}
        options.Authority = "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Vol2qyQFn";
        options.TokenValidationParameters = new()
        {
            ValidateIssuerSigningKey = true,
            ValidateAudience = false
        };
    });

builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/", [Authorize] () =>
{
    return Results.Ok(true);
});

app.Run();

Yukarıdaki kod bloğuna göz atarsanız eğer; 6. satırda AddCognitoIdentity metodu ile uygulamanın authentication ve authorization süreçleri Cognito API’larına göre yapılandırılmakta ve 8 ile 23. satır aralığında ise JWT bearer authentication’a göre şemalar ayarlanmakta ve özellikle authorization server olarakta 17. satırda Cognito belirlenmektedir. 32 ve 35. satır aralığında ise authorize edilerek oluşturulmuş olan bir minimal api mevcuttur.

Şimdi bizler bu API’a direkt bir istekte bulunursak aşağıdaki görselden de anlaşılacağı üzere 401 Unauthorized durumuyla karşılaşacağız..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTBu vaziyette Cognito’dan password grant flow neticesinde gelen access_token değerini aşağıdaki gibi ilgili isteğin header’larında ‘Authorization’ key’ine karşılık Bearer .... şeklinde verirsek aşağıdaki görselde olduğu gibi isteğin başarıyla gerçekleştirildiğini görmüş oluyoruz..NET WebAPI - Amazon Cognito ile Güvenliğin Sağlanması: Serverless Authentication | Client Credentials | Password Flows | JWTNihai olarak;
Geliştirdiğimiz yazılım sistemlerinde kritik noktalardan biri olan authentication ve authorization yapılanmalarını kâh yazılım dahilinde geliştirebilir, kâh merkezi bir authorization server kurmamızı sağlayan OpenIddict veya IdentityServer4 gibi hazır kütüphaneler eşliğinde inşa edebiliriz. Tüm bunların dışında cloud tabanlı olan AWS Cognito sayesinde hem authentication ve authorization sorumluluklarını yapılandırabileceğimiz gibi hem de kullanıcı yönetimi ve Facebook, Google vs. gibi sosyal kimlik sağlayıcılarıyla entegrasyon gibi çeşitli yetenekleri de kolaylıkla gerçekleştirebiliriz. Tercih; önce gereksinimlerin, sonra sizin 🙂

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek çalışmayı aşağıdaki github adresinden edinebilirsiniz.
https://github.com/gncyyldz/Amazon.Cognito.Example

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir