Keycloak — Django Örnek Proje

ergün elvan bilsel
6 min readJan 15, 2023

Keycloak Nedir?
Github’da ki proje sayfalarında yazdığı gibi, “Kimlik ve Erişim Yönetimi” için geliştirilmiş Apache 2.0 ile lisanslanan açık kaynak bir araçtır. Proje Red Hat idaresi altındadır. Keycloak’un sahip olduğu en belirgin özellik;

Uygulamlar da ki kullanıcı doğrulama işlemlerini tek bir noktadan gerçekleştirebilmesidir. Bu sayede kullanıcılar tek bir noktadan oturum açma ve oturum kapatma işlemini gerçekleştirebilmektedir.

Keycloak’un en çok tercih edilme nedeni; kurumların veya şirketlerin hesap işlemlerini tek bir noktadan yönetebilmesidir. Bunu gerekliliğini bir örnekle anlatmaya çalışalım…

Bir şirkete yeni başladınız. Şirketin kullanmış olduğu pek çok uygulama var. Bu uygulamların sorumluluğu farklı departmanlardaki kişilere verilmiş. Uygulamalar tek bir noktadan doğrulama işlemi yapmamakta ve kullanıcı doğrulama ve yetkilendirmesi için şirkette çalışan bir kişiden uygulama sorumlularının isimlerini öğreneceksiniz ve uygulama sorumlusuna gidip hesap açmasını rica edeceksiniz. Yada tüm bu işleri sizin için takım lideriniz halledecek. Her iki kişi içinde bu işlem zaman alacaktır.

Bu işin tam tersini düşünücek olursak. Şirketten ayrılan bir personel için beş sorumlu kişi hesap kaldırma işlemini uygulamak zorunda kalacaktır. Bu işlem zaman açısından maliyetlidir hemde her uygulama için tekrar bir kontrol gerekebilir.

Her uygulama için çok faktörlü kimlik doğrulama, parola yenileme standartı, parola oluşturma prosedürü(en az bir küçük harf,enaz bir büyük harf) gibi uygulama güvenliğini doğrudan etkileyen unsurları için geliştirme ve entegrasyon süreçlerinin ciddi zaman maliyetleri oluşturmaktadır.

Keycloak yukarıda bahsettiğimiz tüm bu aşamalardan tasarruf edebilmek için kurumların ve kişilerin dikkatini çekmektedir. Keycloak ayrıca güçlü oturum yönetim yetenekleriyle tek bir uygulama üzerinde sağlamış olduğunuz otantikasyon üzerinden diğer uygulamalara erişim gerçekleştimeye olanak sağlamaktadır(SSO).

Keycloak diğer özelliklerinden bahsetmek gerekirse;

Web arayüzü

Kullanıcıları ve uygulama ayarlarını yönetebileceğiniz bir arayüz sağlamaktadır. Bu arayüz üzerinden yöneticiler, kimlik kaynağı entegrasyonları, rol ve grup tanımlarını gerçekleştirebilmektedir. Kullanıcılar ise parola yenileme işlemlerini gerçekleştirebilmektedir.

Kullanıcı Kimliği ve Erişimler

Keycloak, özel rollere ve gruplara sahip kullanıcı veritabanı oluşturmanıza izin vermektedir.

Dış Kimlik Kaynağı Senkronizasyonu

LDAP, Active Directory varsayılan olarak desteklemektedir. Bu sayede uygulamalarınız, istemcileriniz için tek bir kullanıcı oluşturabilirsiniz.*

Kimlik Brokerliği

Keycloak, kullanıcılarınız ile bazı harici kimlik sağlayıcıları arasında bir proxy olarak da çalışabilir.

Çoklu Protokol Desteği

Keycloak, OpenID Connect, OAuth 2.0 ve SAML 2.0 olmak üzere üç farklı protokolü desteklemektedir.

— Oauth 2.0: Yetkilendirme işlemleri için kullanılan standartlaşmış bir protokol.

— OpenID Connect: Oauth2.0 protokülünün doğrulama yapabilmesi için üstüne eklenmiş kimlik katmanı olarak düşünebilir.

— SAML: Taraflar arasında, özellikle bir kimlik sağlayıcı ile bir servis sağlayıcı arasında kimlik doğrulama ve yetkilendirme verilerinin değiş tokuş yapılması için kullanılan açık bir standarttır.

Django Nedir?

Django, hızlı geliştirmeyi ve temiz tasarımı teşvik eden üst düzey bir Python web çerçevesidir.

OpenID Connect ile SSO

Örneğimize başlamadan önce öğrenmemiz gereken bir kaç terim var.

RP(Relying Party) : Kısaca güvenen taraf demek. Güvenli bir yazılım uygulamasına(Keycloak) erişim sağlayan bir sunucuya(Django) atfedilmiş bir terimdir.

OP(OpenID Provider): Erişim sağlayan uygulama(Django) için son kullanıcı kimlik doğrulaması yapan ve erişim yetkilerini düzenleyen(Keycloak) sunucudur.

Yukarıdaki terimlerden anlaşıldığı üzere RP => Django, OP =>Keycloak olacaktır. Bir kullanıcı Django üzerindeki app1 veya app2 sayfasına(app1 ve app2 farklı django uygulamalarıdır) erişmek istediği zaman bu sayfaların ``` @login_required ``` dekoratör’ü tarafından kullanıcı oturumu açılmamışsa login URL’ine yönlendirecektir.

@login_required
def index(request):
return HttpResponse('App1')

login_op, kimlik doğrulama isteklerini OP’ye (Keycloak) göndermek için kullanılan bir metod. return OAUTH.rp.authorize_redirect(request, redirect_uri) kimlik doğrulama isteğinden yönlendirme uç noktasına yönlendirme yapılır. Yönlendirme uç noktası, tanımladığımız diğer metoddur (login_rp).

def login_op(request):

redirect_uri = request.build_absolute_uri(
reverse_lazy('oidc:login_rp')
)


if 'next' in request.GET:
request.session['url_next_to_login'] = request.GET['next']


return OAUTH.rp.authorize_redirect(request, redirect_uri)
def login_rp(request):

if 'error' in request.GET:
err_msg = request.GET['error_description']

user = auth.authenticate(request, client=OAUTH.rp)
if user is not None and user.is_authenticated:
auth.login(request, user)

redirect_url = request.session.get('url_next_to_login', settings.LOGIN_REDIRECT_URL)
if 'url_next_to_login' in request.session:
del request.session['url_next_to_login']

return redirect(redirect_url)


return HttpResponse('error')

Kimlik doğrulama istekleri ve kimlik doğrulanması, OAUTHAuthlib nesnelerine aktarılır.

OAUTH = OAuth()
OAUTH.register(
name='rp',
client_id=settings.OIDC_CLIENT_ID,
client_secret=settings.OIDC_CLIENT_SECRET,
access_token_url=settings.TOKEN_ENDPOINT,
authorize_url=settings.AUTHORIZATION_ENDPOINT,
jwks_uri=settings.JWKS_URI,
client_kwargs={
'scope': 'openid',
'code_challenge_method': 'S256',
},
)

OAUTH.register settings.py içerisinde tututalan Keycloak client_id,secret_key,yetkilendirme adresleri bilgilerine ulaşır.

OIDC_CLIENT_ID = 'app1'
OIDC_CLIENT_SECRET = os.environ.get("OIDC_CLIENT_SECRET")
TOKEN_ENDPOINT = 'http://localhost:8080/realms/test/protocol/openid-connect/token'
AUTHORIZATION_ENDPOINT = 'http://localhost:8080/realms/test/protocol/openid-connect/auth'
JWKS_URI = 'http://localhost:8080/realms/test/protocol/openid-connect/certs'

OidcBackend sınıfında mevcut Django BaseBackend sınıfı miras almaktadır ve authenticate metodunu override edilmektedir. Artık OP üzerinden bir access_token elde edililmektedir. Bu token içerisinde kullanıcı bilgisine ulaşılabiliyorsa otantikasyon sağlanmış olur.

from django.contrib.auth.backends import BaseBackend
from django.contrib.auth.models import User


class OidcBackend(BaseBackend):

def authenticate(self, request, client=None):

if client is None:
return None


token = client.authorize_access_token(request)


if token and 'userinfo' in token:
assert 'preferred_username' in token['userinfo']
username = token['userinfo']['preferred_username']
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
user = User(username=username)
user.is_staff = False
user.is_superuser = False
user.save()
return user


return None

def get_user(self, user_id):

try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None

Olayın akış diagramı

Ortamların hazırlanması ve Test

Keycloak

docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin --name keycloak  --network host quay.io/keycloak/keycloak:18.0.1  start-dev

Komutu ile docker ortamında OP sunucumuz hazırlanır. Tarayıcı üzerinden http://localhost:8080/ adresi ile Keycloak ekranına ulaşılır.

User: Admin
Password: Admin

Administration Console sekmesi üzerinden giriş yapılır. Add realm sekmesi (Master Realm üzerinde) yardımıyla “test” isminde bir realm oluşturulur.

RP sunucuna girmiş olduğumuz uç nokta bilgileri Endpoints kısmında ki OpenID Endpoint Configuration kısmından görüntülenebilir.

App1

İstemci oluşturmak için Client sekmesine gidiyoruz. İstemci Protokolü openid-connect olan app1 isminde bir client oluşturuyoruz.

Oluşturmuş olduğumuz istemcide Access Type kısmını ‘confidential’ olarak belirleyip, Valid Redirect kısmına RP sunucumuzdaki OP sunucuna yönlendirme yapacak ve url adresini giriyoruz.

http://localhost:8081/oidc/login/

save butonu ile yaptığımız değişiklikleri kayıt altına alıyoruz. Credentials bölümünde bir adet secret görmekteyiz. Bu key RP sunucuna ekleyerek RP sunucumuzu kaldırıyoruz.

docker run -d --network host  -e OIDC_CLIENT_SECRET=BB9xOcUx1nalEE297XcMffAtEREAXb7B -p 8081:8081 erelbi/app1-keycloak-django-sample

Kendi lab ortamınızda OIDC_CLIENT_SECRET keyi Keycloak sunucunuzdaki key ile değiştirmeyi unutmayın!

Aynı işlemleri app2 içinde gerçekleştirelim. app2 isminde bir client oluşturalım.

http://localhost:8082/oidc/login/

App2

app2 sunucumuzu docker ortamında hazılıyoruz.

docker run -d --network host  -e OIDC_CLIENT_SECRET=1MRQDBBYpeVr2V3WZLCkUknGTApNlcYa -p 8082:8082 erelbi/app2-keycloak-django-sample
+-----------------+----------+-----------------+--------------+------------------+
| Docker | Role | Client Protocol | Access Type | Challenge Method |
+-----------------+----------+-----------------+--------------+------------------+
| localhost 8080 | keycloak | | | |
| localhost 8081 | app1 | openid-connect | confidential | S256 |
| localhost 8082 | app2 | openid-connect | confidential | S256 |
+-----------------+----------+-----------------+--------------+------------------+

Son olarak yukarıdaki tabloda görüldüğü üzere bir keycloak iki django sunucumuz ile SSO lab ortamımızı hazırlamış olduk.

Oluturmuş olduğumuz “test” realm de kullanıcı oluşturuyoruz. Oluşturacağımız bu kullanıcı ile app1 ve app2 uygulamalarına login olabilmeyi hedefliyoruz.

Sol menüdeki Users sekmesinden yeni bir kullanıcı oluşturuyoruz.

Credentials bölümünden oluşturmuş olduğumuz kullanıcıya parola bilgilerini giriyoruz ve ‘set password’ diyip parolasını kaydediyoruz.

Sonuç

--

--