Spring Security Giriş
Spring Security Giriş ve Mimarisi
Spring Security, Java uygulamaları için güçlü ve özelleştirilebilir bir kimlik doğrulama ve erişim kontrolü framework’üdür.
Başlangıçta Acegi Security tarafından geliştirilen ve daha sonra Spring topluluğu tarafından benimsenen Spring Security, Java EE tabanlı kurumsal yazılım uygulamaları için kapsamlı güvenlik hizmetleri sağlar.
Spring Security, Spring tabanlı uygulamaların güvenliğini sağlamak için bir standarttır. Tüm Spring projelerinde olduğu gibi, Spring Security’nin gerçek gücü projeye özel gereksinimleri karşılamak için oldukça kolay özelleştirilebilmesi ve genişletilebilmesidir.
Spring Security’nin Ana Özellikleri
Spring Security’nin ana özelliklerinden bazıları aşağıdaki gibidir:
-
Uygulamalarda kimlik doğrulama ve yetkilendirme için kapsamlı, genişletilebilir destek sunması.
-
Oturum Sabitleme (Session Fixation), clickjacking, CSRF (Cross Site Request Forgery) gibi birçok saldırıya karşı yüzey alanını azaltarak önlem alması. Söz konusu saldırıların kısaca açıklamaları aşağıdaki gibidir.
- Oturum Sabitleme: Bir kullanıcının oturum kimliğinin (session id) saldırgan tarafından önceden belirlenip, bu kimlikle oturum açmasının sağlandığı bir güvenlik açığıdır.
- Clickjacking: Bir kullanıcının farkında olmadan başka bir şeyin (buton vb.) üzerine tıklamasını sağlayan bir siber saldırı tekniğidir.
- CSRF: Oturumu açık olan bir kullanıcının tarayıcısı üzerinden, haberi olmadan başka bir web sitesine yetkili bir işlem yaptırılmasıdır.
-
Gelen istekleri kesmek ve güvenlik kontrolleri veya eylemleri uygulamak için filtreler, engelleyiciler kullanılması.
-
Servlet API entegrasyonu sunması
-
Spring Web MVC ile isteğe bağlı entegrasyon gerçekleştirilebilmesi
Spring Boot ve Spring Security’nin Sağladığı Özellikler
Spring Boot ve Spring Security’nin varsayılan olarak çalıştığında neleri bizim için düzenlediğine bakalım:
-
Spring Boot’un /error endpoint’i de dahil olmak üzere herhangi bir endpoint için kimliği doğrulanmış bir kullanıcı ister. Bu sayede her isteğin doğrulanmasını gerektirir.
-
Spring’in bize sağladığı kurallar ile ilgili özelleştirme ve genişletme yapabilme kabiliyetleri sayesinde çoğu kullanım durumunda tanımladığımız yetkilendirme kuralları varsayılan olan kurallardan daha karmaşık olacaktır.
-
Başlangıçta oluşturulan bir parola ile varsayılan bir kullanıcıyı kaydeder. Parola ayrıca konsola kaydedilir. Örnek: ”Using generated security password: 8e557245-73e2-4286-969a-ff57fe326336”
-
Parolaların depolanmasını BCrypt ile korur. PasswordEncoder ile entegre olarak parolaların güvenli bir şekilde saklanmasını sağlar.
-
Form tabanlı olarak basit bir şekilde oturum açma ve oturum kapatma özelliklerini sağlar. Form tabanlı oturum açma kimliğini doğrular.
-
Web istekleri için oturum açma sayfasına yönlendirirken; hizmet istekleri için 401 Unauthorized dönülmesini sağlar.
-
Session Fixation. CSRF, Sniffing, Clickjacking gibi saldırıların azaltılmasını sağlar.
-
HTTPS kullanıldığından emin olur.
-
Kimliği doğrulanmış kaynakları korumak için “Cache Control headers”’ı kullanır. İstenilirse Spring Securty’nin “cache control” mekanizması devre dışı bırakılabilir.
-
HttpServletRequest’in kimlik doğrulama yöntemleri ile entegredir.
-
Kimlik doğrulamanın başarılı veya başarısız olduğu hakkında bilgilendirme yapar.
Spring Boot’un otomatik konfigürasyonu:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@EnableWebSecurity
@Configuration
public class DefaultSecurityConfig {
@Bean
@ConditionalOnMissingBean(UserDetailsService.class)
InMemoryUserDetailsManager inMemoryUserDetailsManager() {
String generatedPassword = // ...;
return new InMemoryUserDetailsManager(User.withUsername("user")
.password(generatedPassword).roles("ROLE_USER").build());
}
@Bean
@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher(ApplicationEventPublisher delegate) {
return new DefaultAuthenticationEventPublisher(delegate);
}
}
-
@EnableWebSecurity anotasyonunu ekler.
-
UserDetailsService @Bean’i kullanıcı adı ve başlangıçta konsola kaydedilen rastgele oluşturulmuş bir parola ile paylaşır.
-
Kimlik doğrulama olaylarını paylaşmak için bir AuthenticationEventPublisher @Bean oluşturur.
Spring Boot, @Bean olarak yayınlanan herhangi bir Filtreyi uygulamanın filtre zincirine ekler. Bu, @EnableWebSecurity’nin Spring Boot ile birlikte kullanılmasının, her istek için Spring Security’nin filtre zincirini otomatik olarak kullanıldığı anlamına gelir.
Bu konfigürasyonda oluşturulan Spring Bean’leri aşağıdaki gibi kısaca açıklanabilir.
- Spring Security’de UserDetailsService, kullanıcı bilgilerini (kullanıcı adı, şifre, roller vs.) yüklemek için kullanılan bir arayüzdür. Oluşturulan InMemoryUserDetailsService tipindeki bean ise geliştirici tarafından özel bir UserDetailsService bean’i tanımlanmadığı durumlarda kullanıcı bilgilerini bellek içi (veritabanı vb.) almasını sağlayan varsayılan bir yapı olarak tanımlanmıştır.
- AuthenticationEventPublisher, Spring Security’de gerçekleşen kimlik doğrulama olaylarını (başarılı ya da başarısız giriş denemeleri gibi) uygulamanın geri kalanına duyurmak için kullanılan bir arayüzdür. Oluşturulan DefaultAuthenticationEventPublisher bean’i ise geliştirici tarafından özel bir yapı oluşturulmadığı durumlarda varsayılan olarak kullanılmak üzere tanımlanmıştır.
Spring Security’nin Kullanım Durumları
Spring security’nin çok sayıda kullanım durumu var. Uygulamamızda kullanmaya karar vermeden önce Spring Security’nin ele almak üzere tasarlandığı bazı yaygın kullanım durumlarını göz önünde bulundurabiliriz.
- Bir REST API oluşturuyorsak ve bir JWT veya başka bir Token-Based Authentication yöntemi kullanmamız gerekiyorsa,
- Bir web uygulaması, API Gateway veya BFF oluştururken: OAuth 2.0 veya OIDC kullanarak giriş yapmamız gerekiyorsa, SAML 2.0, CAS kullanmamız gerekiyorsa,
- LDAP veya Active Directory’de bulunan kullanıcıları Spring Data veya JDBC ile yönetmemiz gerekiyorsa,
- Kullanıcıların şifrelerinin yönetilmesi gerekiyorsa
Bunu yanı sıra aşağıdaki konu başlıkları üzerinden de kullanım durumları incelenebilir:
Protocol: İlk olarak uygulamamızın iletişim kurmak için kullanacağı protokolü düşünmeliyiz.
- Spring Security, HTTP’nin yanı sıra Websocket’leri de desteklemekte.
Authentication: Kullanıcıların nasıl kimlik doğrulaması yapacağını düşünmeliyiz.
Authorization: Kullanıcıların ne yapmaya yetkili olduğunu nasıl belirlemek istediğimize yani yetkilendirmenin nasıl yapılacağına karar vermeliyiz.
Defense: Varsayılan koruma ayarlarının yeterli olup olmadığı, uygulamamız için gerektiğinde ek koruma yöntemlerini kolay şekilde entegre edip edemeyeceğimizi düşünmeliyiz.
Genel olarak Spring Security kimlik doğrulama, yetkilendirme ve diğer güvenlik özellikleri gerektiren uygulamalarda kullanılır. Kaynakları korumanın ve erişim kontrolünü yönetmenin gerekli olduğu web uygulamaları, RESTful hizmetleri, mikro hizmetler ve diğer Java tabanlı uygulama türleri için uygun olduğunu söyleyebiliriz.
Spring Security’nin Hedefleri
Kapsamlı Güvenlik (Comprehensive Security): Uygulama güvenliğini sağlamak için gerekli tüm araçları ve mekanizmaları geliştiricilere sağlamak.
Modülerlik (Modularity): Geliştiricilerin ihtiyaçlarına göre belirli modülleri veya özellikleri eklemelerine izin vermek.
Kullanım Kolaylığı (Ease of Use): Geliştiricilere uygulaması kolay olan bir API ve yapılandırma sunmak.
Entegrasyon (Integration): Diğer Spring modülleri ve üçüncü taraf güvenlik sistemleri ile sorunsuz entegre edilebilmesi ve kullanılabilmesi. Bazı entegrasyonları aşağıdaki gibidir.
-
Spring Boot ile Entegrasyon
- Spring Boot, Spring Security’yi otomatik olarak yapılandırır. Varsayılan güvenlik ayarları sağlanır ve özelleştirmeler için SecurityConfig sınıfı kullanılır.
-
Spring MVC ile Entegrasyon
- Web güvenliğini sağlamak için URL erişim izinleri ve kimlik doğrulama işlemleri yapılır.
-
Spring Data JPA ile Entegrasyon
- Veritabanından kullanıcı bilgilerini almak için UserDetailsService kullanılır ve güvenli kimlik doğrulama sağlanır.
-
Spring OAuth2 ve OpenID Connect ile Entegrasyon
- Dış kimlik sağlayıcıları (Google, Facebook vb.) ile OAuth2 veya OpenID Connect üzerinden kimlik doğrulama yapılır.
-
Spring Session ile Entegrasyon
- Oturum verilerinin merkezi bir şekilde yönetilmesi için Spring Session kullanılır.
-
Spring Cloud ile Entegrasyon
- Mikroservisler arasında güvenliği sağlamak için OAuth2 veya JWT gibi protokoller kullanılır.
-
Spring Actuator ile Entegrasyon
- Actuator uç noktalarına erişimi sınırlamak için Spring Security ile güvenlik eklenir.
Sağlamlık (Robustness): Güncel şekilde güvenlik mekanizmalarının sağlam olduğundan ve çeşitli saldırı şekillerini ele alabilecek kapasitede olduğundan emin olmak.
Spring Security’nin Artıları ve Eksileri
Artılar:
-
Sağlam Güvenlik Özellikleri (Robust Security Features): Şifreleme, kimlik doğrulama, yetkilendirme, CSRF koruması ve daha fazlası dahil olmak üzere çok çeşitli güvenlik özelliklerini sağlaması.
-
Özelleştirme (Customization): Konfigürasyon yoluyla oldukça özelleştirilebilir olması. Geliştiricilerin güvenlik özelliklerini belirli uygulama gereksinimlerine göre uyarlamasına olanak tanıması.
-
Entegrasyon (Integration): Spring ekosistemiyle sorunsuz bir şekilde entegre olarak diğer Spring modülleriyle birlikte kolay kullanım sağlar.
-
Destek ve Topluluk (Support and Community): Geniş bir topluluk, kapsamlı dokümantasyon ve kaynaklar tarafından desteklenir.
-
Ölçeklenebilirlik (Scalability): Küçük uygulamalardan büyük kurumsal sistemlere kadar iyi ölçeklenir.
Eksiler:
-
Dik Öğrenme Eğrisi (Steep Learning Curve): Kapsamlı özellikleri ve konfigürasyonları nedeniyle öğrenirken zorluklar oluşturabilir. Bu noktada Spring Security adaptasyonunun kolaylaştırılması açısından adım adım öğrenmeye başlamak önemlidir. Öncelikle güvenlik kavramları araştırılmalı ve kavranmalıdır. Burada basitten karmaşığa doğru ilerlenmelidir. Örneğin yetkilendirme ve kimlik doğrulama kavramlarının farkları ile başlanıp OAuth2 ve JWT gibi kavramlara doğru ilerlemek daha kolay kavramayı sağlayabilir. Spring Security öğrenme yolunda Spring Boot ile çalışılması da faydalı olacaktır çünkü Spring Boot, Spring Security için varsayılan konfigürasyonlar sağlar.
-
Karmaşık Konfigürasyonlar (Complex Configurations): Spring Security’yi uygulamadaki karmaşık kullanım durumları için yapılandırmak detaylı bilgi ve uzmanlık gerektirebilir. Bu noktada da ilk maddedeki gibi ilerlemek faydalı olacaktır. Örneğin karmaşık konfigürasyonların çözülmesi noktasında Spring Boot’un sağladığı varsayılan konfigürasyonların incelenmesi ve kullanımı faydalı olacaktır.
-
Bakım Zorlukları (Maintenance Challenges): Konfigürasyonları yönetmek, çok fazla özelleştirme içeren büyük uygulamalarda gittikçe karmaşık hale gelebilir.
Spring Security Mimarisi
Spring Security’nin Servlet desteği Servlet Filtrelerinden gelmektedir. Bu nedenle filtre rollerini incelemek önemlidir.
Servlet filtreleri, bir web uygulamasında gelen istekleri ve cevapları işlemek için kullanılan filtrelerdir. Uygulamaya bir istek geldiğinde ve bu istek için cevap dönüleceğinde devreye girerler. Güvenlik, loglama, veri doğrulama, sıkıştırma ve yönlendirme gibi işlemleri gerçekleştirebilirler. Filtreler, bir istek işlendikten sonra zincir şeklinde diğer filtrelere iletilir ve her filtre, isteği veya yanıtı değiştirebilir. Bu sayede, uygulama çapında merkezi bir güvenlik politikası veya işlem yönetimi sağlanabilir.
Aşağıdaki resimde, bir HTTP isteği için örnek bir filter chain gösterilmektedir:
-
Client uygulamaya bir istek gönderir ve container isteğin URI adresine göre HttpServletRequest’i işlemesi gereken filtreleri ve Servlet’i içeren bir FilterChain yapısı oluşturur. Bir Servlet en fazla tek bir HttpServletRequest ve HttpServletResponse yönetirken farklı amaçlarda kullanılan birden fazla Filtre kullanılabilir.
-
Filtreler, sonraki filtrelerin veya Servlet’in çalışmasını engelleyebilir. Bu gibi durumlarda, Filtreler genellikle HttpServletResponse’u değiştirir. Aynı zamanda, HttpServletRequest veya HttpServletResponse’u değiştirerek diğer filtreleri ve Servlet’in davranışını etkileyebilir.
-
Filtrenin etkinliği, kendisine aktarılmış olan FilterChain’e dayanır. Request ve response akışını kontrol etmesine ve değiştirmesine olanak tanır.
1
2
3
4
5
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before the rest of the application
chain.doFilter(request, response); // invoke the rest of the application
// do something after the rest of the application
}
- Bir Filtre yalnızca aşağı yöndeki filtre örneklerini ve Servlet’i etkilediğinden, her filtrenin çağrılma sırası son derece önemlidir.
DelegatingFilterProxy
Spring’in DelegatingFilterProxy’si Servlet konteyneri ile Spring’in ApplicationContext’i arasında bir köprü görevi görür. Servlet kendi filtre kayıt mekanizması ile çalışır ancak Spring tanımlı beanler hakkında bilgisi yoktur.
DelegatingFilterProxy’yi standart Servlet mekanizmaları aracılığıyla kaydedebiliriz ancak bu durumda tüm işi Filter’ı uygulayan bir Spring Bean’e devretmeliyiz.
DelegatingFilterProxy, ApplicationContext’ten Bean Filter0’ı bulur ve ardından Bean Filter0’ı çağırır.
FilterChainProxy
Spring Security’nin Servlet desteği FilterChainProxy içinde yer alır.
FilterChainProxy, Spring Security tarafından sağlanan ve SecurityFilterChain aracılığıyla birçok filtre örneğine temsilci atanmasına olanak tanıyan özel bir filtredir.
Mimarinin yapı taşlarının birleşimi aşağıdaki gibidir:
DelegatingFilterProxy Servlet konteyneri içindeki FilterChainProxy için bir proxy görevi görür. FilterChainProxy’nin kaydedilmesini ve çağrılmasını sağlar. Bu sayede SecurityFilterChains içinde yapılandırılmış birden fazla filtrenin uygulanmasını düzenler.
FilterChainProxy Spring Security tarafından sağlanan ve merkezi bir dağıtıcı görevi gören özel bir filtredir. Gelen isteklerin SecurityFilterChain içinde düzenlenen birden fazla filtreye iletilmesine izin verir.
SecurityFilterChain URL modellerine veya güvenlik yapılandırmalarına özgü bir filtre zinciri tanımlar. Her SecurityFilterChain belirli bir filtre kümesiyle ilişkilendirilir ve uygulamanın spesifik bölümlerine uygulanır.
Security Filters
Güvenlik Filtreleri, SecurityFilterChain yardımı ile FilterChainProxy’ye eklenir. Bu filtreler kimlik doğrulama, yetkilendirme, exploit koruması vb. birçok amaç için kullanılabilir. Filtrelerin, doğru zamanda çağrılmasını sağlamak için belirli bir sırada çalıştırılır; örneğin, kimlik doğrulama gerçekleştiren filtre, yetkilendirme gerçekleştiren filtreden önce çağrılmalıdır.
Spring Security filtrelerinin sıralamasını bilmek zorunlu değildir. Ancak sıralamayı bilmenin faydalı olduğu durumlar vardır, sıralamayı öğrenmek için FilterOrderRegistration.java kodunu inceleyebiliriz.
Uygulanan filtrelerin listesi uygulama başlangıcında INFO şeklinde yazdırılır, böylece konsol çıktısında veya istenirse log olarak filtrelere bakılabilir.
Güvenlik Filtresi Örneği:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(Customizer.withDefaults())
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
return http.build();
}
}
-
CSRF saldırılarına karşı koruma sağlamak için CsrfFilter çağrılır,
-
İsteğin kimliğini doğrulamak için kimlik doğrulama filtreleri çağrılır,
-
İsteği yetkilendirmek için AuthorizationFilter çağrılır.
Authentication ve Spring Authentication Architecture
Authentication temel kullancının beyan ettiği kullancı olduğunu doğrulamaktır. Bu işlem üç yolla yapılabilir;
-
Güvenilir bir üçüncü kişinin sözü referans alınarak
-
Hali hazırda doğrulanmış bir obje ile karşılaştırarak
-
Doğrulayıcı tarafından bilinen bilgileri sunarak
Doğrulama faktörleri de temelde üçe ayrılmış vaziyettedir. Kullanıcının;
-
Sahip olduğu bilgi(Knowledge)
-
Sahip olduğu obje, anahtar vb.(Ownership)
-
Ne olduğu(Inherence)
özelliklerine göre ayrılabilir.
Bu yollardan sadece bir tanesini kullanarak yapılan doğrulama işlemleri Single Factor Authentication olarak adlandırılır. İki ve ikiden fazla yöntemin kullanılması da Two Factor Authentication ve Multi Factor Authentication şeklinde adlandırılmıştır.
Spring Security, Authentication için kapsamlı destek sağlar. Destek sağladığı kimlik doğrulama yöntemlerinden bazıları:
-
Kullanıcı adı ve şifre: En yaygın yöntem olup, kullanıcının kimliğini kullanıcı adı ve şifre ile doğrular.
-
OAuth 2.0 Tabanlı Giriş: Harici sağlayıcılar (Google, GitHub vb.) üzerinden kimlik doğrulama sağlar.
-
SAML 2.0 Tabanlı Giriş: Kurumsal sistemlerde kullanılan XML tabanlı bir kimlik doğrulama protokolüdür.
-
Merkezi Kimlik Doğrulama Hizmeti (Central Authentication Service) (CAS): Tek oturumla birden fazla uygulamaya giriş yapılmasını sağlayan merkezi kimlik doğrulama sistemidir.
-
JAAS Kimlik Doğrulama: Java tabanlı uygulamalarda modüler kimlik doğrulama ve yetkilendirme desteği sunar.
-
X509 Kimlik Doğrulama: Kullanıcıyı dijital sertifikalarla (genellikle SSL üzerinden) doğrulayan yöntemdir.
Spring Authentication Architecture
Spring Security içerisinde Servlet kimlik doğrulama mimarisi (Servlet Authentication Architecture) temelli bir kimlik doğrulama mekanizması sunmaktadır.
Servlet kimlik doğrulama mimarisi, bir kullanıcının web uygulamasına erişmek istediğinde önce kimliğinin doğrulanmasını, ardından yetkilerinin kontrol edilerek ilgili kaynaklara erişimin sağlanmasını içeren bir güvenlik yapısıdır. Kullanıcıdan genellikle kullanıcı adı ve parola istenir; bu bilgiler doğrulanır. Doğrulama başarılı olursa, kullanıcıya bir oturum açılır ve yetkili olduğu sayfalara erişim verilir; aksi takdirde erişim reddedilir.
- SecurityContextHolder
Spring Security’de kimliği doğrulanan kişinin ayrntlarının depolandığı yerdir.
- SecurityContext
SecurityContextHolder’dan elde edilir ve o anda kimliği doğrulanmış kullancının kimlik doğrulama bilgisini içerir.
SecurityContext, bir kullanıcının kimliğini ve yetkilerini uygulama boyunca taşıyan bir yapıdır. İçinde genellikle Authentication nesnesi bulunur; bu nesne de kullanıcının kullanıcı adı, şifresi, yetkileri ve kimlik doğrulama durumu gibi bilgileri barındırır. SecurityContext’in temel amacı, bir isteğin hangi kullanıcıya ait olduğunu ve bu kullanıcının uygulama içinde hangi işlemleri yapmaya yetkili olduğunu belirlemektir.
- Authentication
Kimlik doğrulama için kullanıcı tarafından sağlanan kimlik bilgilerini veya başarılı bir kimlik doğrulama işleminden sonra SecurityContext’de depolanan kimliği doğrulanmış kullanıcı bilgilerini ifade eder.
- GrantedAuthority
Authentication için kişiye verilen yetkiler. (roller, kapsamlar vb.)
- AuthenticationManager
Spring Security filtrelerinin kimlik doğrulamayı nasıl gerçekletireceiğni tanımlayan API. Filtrelere bir arayüz olarak kullanılması bir doğrulama mekanizması tanımlanmasını sağlar.
- ProviderManager
AuthenticationManager’ın en yaygın uygulamasıdr.
- AuthenticationProvider
ProviderManager tarafından spesifik bir kimlik doğrulama türünü gerçekleştirmek için kullanılır.
- Request Credentials
İsteği gönderen istemcinin kimlik bilgilerini öğrenmek için kullanılır (Oturum açma sayfasna yönlendirme, WWW-Authenticate cevabını gönderme vb.)
- AbstractAuthenticationProcessingFilter
Kimlik doğrulaması için kullanılan temel bir güvenlik filtresi.
SecurityContextHolder
Spring Security’de kimlik doğrulamanın merkezinde SecurityContextHolder yer alır ve SecurityContext’i içerir.
Spring Security’de kimliği doğrulanan kullancıya ilişkin bilgilerin depolandığı yerdir. Burada yer alan authentication örneğinde yer alan bilgilere sahip kullanıcı doğrulanmış demektir. Dolayısıyla kullancının kimliğini doğrulamanın en basit yolu doğrudan SecurityContextHolder’a kayıt etmektir.
1
2
3
4
SecurityContext context = SecurityContextHolder.createEmptyContext(); (1)
Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER"); (2)
context.setAuthentication(authentication); (3)
SecurityContextHolder.setContext(context); (4)
-
Boş bir SecurityContext oluşturulur.
-
Ardından yeni bir Authentication nesnesi oluşturulur. (Spring SecurityContext üzerine hangi tipte bir authentication yöntemi ayarladığımızla ilgilenmez.)
-
Authentication nesnesi SecurityContext’e atanır.
-
Son aşamada ise SecurityContextHolder üzerinde SecurityContext atanır. Spring Security bu bilgiyi yetkilendirme için kullanır.
SecurityContextHolder aracılığı ile authentication bilgilerine aşağıdaki şekilde erişebiliriz:
1
2
3
4
5
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
- Örneklerden anlaşıldığı üzere, SecurityContextHolder içerisinde bulunan ve authentication örneğini sarmalayan yapı SecurityContext’tir. Bu yapı ile authentication örneğini yönetebiliriz.
Authentication
Authentication, kimlik doğrulama için kullanıcı tarafından sağlanan kimlik bilgilerini veya başarılı bir kimlik doğrulama işleminden sonra SecurityContext ‘de depolanan kimliği doğrulanmış kullanıcı bilgilerini ifade eder.
-
Spring Security içerisinde bulunan Authentication arayüzü, iki amaçla kullanılır;
-
AuthenticationManager implementasyonlarına sağlanarak kimlik doğrulama işlemlerinin gerçekleştirilmesi.
-
SecurityContextHolder üzerinde bulunan SecurityContext içerisinde bulunan Authentication örneğinin elde edilmesi.
-
Bir Authentication örneği, üç bilgiyi içerir;
-
principal: Kullanıcının kimliğini temsil eden bilgiyi içerir. (username, email vb.)
-
credentials: Kullanıcının kimliğini doğrulamak için kullanılan bilgiyi içerir. (password, pin vb.)
-
authorities: Kullanıcının sahip olduğu yetkileri içerir. (roller, kapsamlar vb.)
Authentication örneği, kimlik doğrulama işleminin başarılı olup olmadığını belirten bir boolean değer içerir. Bu değer, isAuthenticated() metodu ile elde edilebilir.
Authentication örneği, kimlik doğrulama işleminin başarılı olması durumunda;
-
Kimlik doğrulama işleminin gerçekleştirildiği AuthenticationProvider örneğini içerir. Bu değer, getAuthenticationProvider() metodu ile elde edilebilir.
-
Kimlik doğrulama işleminin gerçekleştirildiği AuthenticationProvider örneğinin kimlik doğrulama işlemini gerçekleştirdiği Authentication örneğini içerir. Bu değer, getAuthentication() metodu ile elde edilebilir.
GrantedAuthority
SpringSecurity içerisinde kullanıcı bilgilerini taşımak ve yönetmek için genellikle UserDetails ve UserDetailsService arayüzleri kullanılır. Bu arayüzlerin kullanılması durumunda, kullanıcıya ait yetkileri tutmak için GrantedAuthority arayüzü kullanılır. Bu arayüz, kullanıcının sahip olduğu yetkileri temsil eder. (roller, kapsamlar vb.)
Bu yapı ayrıca Authentication arayüzü içerisinde de kullanılır. Authentication arayüzü içerisinde bulunan getAuthorities() metodu ile kullanıcının sahip olduğu yetkiler elde edilebilir.
Spring Security içerisinde, kullanıcının sahip olduğu yetkileri temsil etmek için SimpleGrantedAuthority ve GrantedAuthorityImpl sınıfları kullanılır.
-
Bu sınıflar, GrantedAuthority arayüzünü implemente eder.
-
Bu sınıfların kullanılması durumunda, kullanıcının sahip olduğu yetkileri temsil etmek için String tipinde bir değer kullanılır.
-
Bu değer, GrantedAuthority arayüzünün tek metodu olan getAuthority() metodu ile elde edilebilir. Bu değer, kullanıcının sahip olduğu yetkileri temsil eder. (ROLE_USER, ROLE_ADMIN vb.).
-
Bu değerler, Spring Security tarafından kullanılan ROLE_ ön eki ile başlamalıdır. Aksi durumda, Spring Security tarafından yetki olarak algılanmazlar.
1
2
3
4
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(authority);
UserDetails userDetails = new User("username", "password", authorities);
Örnek kullanım olarak, @PreAuthorize anotasyonu kullanılabilir. Bu anotasyonlar, kullanıcının sahip olduğu yetkileri temsil eden String değerlerini parametre olarak alır. Bu değerler, Spring Security tarafından kullanılan ROLE_ ön eki ile başlamalıdır. Aksi durumda, Spring Security tarafından yetki olarak algılanmazlar.
1
2
3
4
@PreAuthorize("hasRole('ROLE_USER')")
public void method() {
//...
}
AuthenticationManager & ProviderManager
Uygulamalarımızda farklı kimlik doğrulama yöntemleri kullanabiliriz. Örneğin, kullanıcı adı ve parola ile kimlik doğrulama, LDAP ile kimlik doğrulama, OpenID ile kimlik doğrulama vb. Bu kimlik doğrulama yöntemlerini AuthenticationManager arayüzü ile yönetebiliriz.
Bu arayüzden implement eden sınıflar, farklı kimlik doğrulama işlemlerinden sorumlu olabilir. En yaygın kullanılan AuthenticationManager implementasyonu ise ProviderManager sınıfıdır. Her bir ProviderManager sınıfı, farklı bir kimlik doğrulama yöntemini temsil edebilir.
Bir ProviderManager, birden fazla AuthenticationProvider örneğini yönetebilir ve farklı tipte doğrulama tekniklerini bu seviyede de kullanabilir. Bu örneklere, authenticate() metodu ile erişilebilir. Bu metot, kimlik doğrulama işlemini gerçekleştirir. Bu işlem başarılı olursa, Authentication örneği döndürülür. Aksi durumda, AuthenticationException fırlatılır.
Bir authentication örneği sisteme giriş yaptığında, uygun bir AuthenticationProvider aranır. Bu işlem, AuthenticationProvider arayüzünü implemente eden sınıfların supports() metodu ile gerçekleştirilir. Bu metot, AuthenticationProvider sınıfının desteklediği authentication türünü belirtir. Eğer AuthenticationProvider sınıfı, Authentication örneğini destekliyorsa, authenticate() metodu ile kimlik doğrulama işlemi gerçekleştirilir. Aksi durumda, herhangi destekleyen bir sınıf bulunamaz ise ProviderNotFoundException fırlatılır.
AuthenticationProvider
AuthenticationProvider, kimlik doğrulama işlemini gerçekleştiren sınıfların implement etmesi gereken arayüzdür. Bu arayüz, kimlik doğrulama işlemini gerçekleştiren authenticate() metodu içerir. Bu metot, Authentication örneğini parametre olarak alır ve gerekli durumda AuthenticationException fırlatır.
AuthenticationProvider arayüzünü implemente eden sınıflar, Authentication örneğini destekleyip desteklemediğini belirtmek için supports() metodu ile kontrol edebilir. Bu metot, Authentication örneğini parametre olarak alır ve boolean değer döndürür. Eğer AuthenticationProvider sınıfı, Authentication örneğini destekliyorsa, authenticate() metodu ile kimlik doğrulama işlemi gerçekleştirilir. Aksi durumda, herhangi destekleyen bir sınıf bulunamaz ise ProviderNotFoundException fırlatılır.
Spring Security içerisinde, AuthenticationProvider arayüzünü implemente eden sınıfların en yaygın örneklerinden biri DaoAuthenticationProvider sınıfıdır.
-
Bu sınıf, kullanıcı bilgilerini veritabanından alır ve kimlik doğrulama işlemini gerçekleştirir.
-
AuthenticationProvider arayüzünü implemente eder ve Authentication örneğini destekler.
-
Bu sınıfın kullanılması için, UserDetailsService arayüzünü implemente eden bir sınıfın kullanılması gerekir.
-
Kullanıcı bilgilerini veritabanından alır ve UserDetails arayüzünü implemente eden bir sınıfın örneğini döndürür.
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
return provider;
}
Serinin bir sonraki yazısına Basic Authentication, OAuth2 ve Token-Based Authentication Yaklaşımları adresinden ulaşabilirsiniz.
Kaynakça