Er ya da geç büyük bir müşteri şu soruyu sorar: personelimiz sizin uygulamanıza şirket hesabıyla oturum açabilir mi? Kastettikleri bir kullanıcı adı ve şifre daha değildir. Kastettikleri, zaten her şey için kullandıkları Microsoft Entra ID, Okta veya AD FS oturum açma yöntemidir; kendi şifre politikaları, kendi iki faktörlü doğrulamaları ve birisi ayrıldığında bir hesabı kapatabilecekleri tek bir yer ile birlikte.
Kimlik ekiplerinin beklediği yanıt SAML 2.0'dır. Yeni oturum açma bileşenlerine genel bakış yazısında SAML yalnızca bir paragraf yer buldu. Bu yazı akışın tamamını ele alıyor: TsgcSAMLServiceProvider'ın ne yaptığı, bir oturum açma sayfasının ve Assertion Consumer Service'in kodu, uygulamanızı yaygın identity provider'lara nasıl kaydettireceğiniz ve tüm bunları hiçbir yerde hesabınız olmadan bugün nasıl test edeceğiniz.
SAML Oturum Açma Nasıl Çalışır
Üç taraf yer alır. Uygulamanız service provider'dır (SP). Müşterinin dizini identity provider'dır (IdP). Tarayıcı, mesajları ikisi arasında taşır, bu yüzden sunucunuz ile IdP hiçbir zaman doğrudan konuşmaz.
- Kullanıcı oturum açma URL'nizi açar. Uygulamanız bir AuthnRequest oluşturur ve tarayıcıyı IdP'ye yönlendirir.
- IdP, şirketin belirlediği şifre, MFA veya koşullu erişim kurallarıyla kullanıcının oturumunu açar.
- IdP imzalı bir SAMLResponse ile yanıt verir, ve tarayıcı bunu Assertion Consumer Service (ACS) URL'nize POST eder.
- Uygulamanız yanıtı doğrular ve içinde belirtilen kullanıcı için kendi oturumunu oluşturur.
Dördüncü adım, SAML uygulamalarının yanlış gittiği yerdir ve bileşenin sizin adınıza yaptığı kısım tam olarak budur.
Service Provider, Adım Adım
TsgcSAMLServiceProvider bir HTTP sunucusu değildir. SAML mesajlarını oluşturur ve kontrol eder; onu, uygulamanızın zaten sahip olduğu sunucunun istek işleyicisinden çağırırsınız, örneğin bir TsgcWebSocketHTTPServer veya bir TsgcHTTPServer.
- Uygulamanızı tanımlayın. Uygulamanızın benzersiz adı olan (genellikle metadata URL'si)
EntityID'yi ve yanıtın ulaştığı https URL'si olanAssertionConsumerServiceURL'yi ayarlayın. - Identity provider'ı tanımlayın. IdP metadata belgesiyle
LoadIdPMetadata'yı çağırın. Bu, IdP'nin entity ID'sini, oturum açma URL'sini ve binding'ini, ve tüm imzalama sertifikalarını okur. Metadata yoksaIdPEntityID,IdPSSOURLveIdPCertificates'ı elle ayarlayın. - İsteği gönderin.
GetAuthnRequestRedirectURL, tarayıcının yönlendirileceği URL'yi döndürür. Yalnızca HTTP-POST binding sunan bir IdP için,GetAuthnRequestPostFormbunun yerine isteği POST eden bir sayfa döndürür. - İstek id'sini saklayın. Her iki yöntem de yeni AuthnRequest'in id'sini döndürür. Bunu sunucuda, rastgele bir RelayState veya oturum çerezine göre indekslenmiş şekilde saklayın, ve yanıt ulaştığında kaldırın, böylece her istek yalnızca bir kez yanıtlanabilir.
- Yanıtı işleyin. ACS URL'sinde, POST edilen SAMLResponse, RelayState ve saklanan istek id'siyle
ProcessResponse'ı çağırın.Truedöndürdüğünde, birTsgcSAMLResult,NameID'yi,SessionIndex'i ve IdP'nin gönderdiği tüm nitelikleri içerir.Falsedöndürdüğünde,ErrorMessagenedenini belirtir veOnSAMLErrortetiklenir.
EntityID, AssertionConsumerServiceURL ve LoadIdPMetadata başlangıçta bir kez ayarlandığında, oturum açma sayfası ve ACS tek bir istek işleyicisine sığar:
uses
sgcAuth_SAML_SP;
procedure TMyApp.OnCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
vRelayState, vRequestID: string;
oResult: TsgcSAMLResult;
begin
if ARequestInfo.Document = '/saml/login' then
begin
// 1. send the browser to the identity provider
vRelayState := NewRelayState;
AResponseInfo.Redirect(FSAML.GetAuthnRequestRedirectURL(vRelayState,
vRequestID));
// 2. keep the request id, the response must answer it
AddPendingRequest(vRelayState, vRequestID);
end
else if (ARequestInfo.Document = '/saml/acs') and
SameText(ARequestInfo.Command, 'POST') then
begin
// 3. the browser posts SAMLResponse and RelayState back
vRelayState := ARequestInfo.Params.Values['RelayState'];
vRequestID := TakePendingRequest(vRelayState);
oResult := TsgcSAMLResult.Create;
try
if FSAML.ProcessResponse(ARequestInfo.Params.Values['SAMLResponse'],
vRelayState, vRequestID, oResult) then
begin
// 4. signed in: create your own session for this user
CreateUserSession(AResponseInfo, oResult.NameID, oResult.SessionIndex);
AResponseInfo.Redirect('/');
end
else
AResponseInfo.ResponseNo := 403; // log oResult.ErrorMessage
finally
oResult.Free;
end;
end;
end;
NewRelayState, AddPendingRequest, TakePendingRequest ve CreateUserSession, kendi kodunuzu temsil eder: bir GUID, RelayState'e göre indekslenmiş ve her istek id'sini yalnızca bir kez veren thread safe bir liste, ve uygulamanızın oturum çerezi. Nitelikler Name=Value satırları olarak gelir, bu yüzden oResult.Attributes.Values['email'] bunlardan birini adına göre okur. Entra ID bunları http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress gibi claim URI'leriyle adlandırır.
RelayState, IdP imzası tarafından kapsanmaz. Onu kendi bekleyen isteğinizi bulmak için bir anahtar olarak kullanın, asla kontrol etmeden yönlendirdiğiniz bir URL olarak değil.
Uygulamanızı Identity Provider'a Kaydettirin
GetMetadata, service provider metadata'sını döndürür: entity ID'niz ve HTTP-POST binding'e sahip ACS URL'niz. Bunları /saml/metadata gibi bir URL'de sunun veya bir dosyaya kaydedin, ve IdP'ye verin. Her identity provider aynı iki değeri ister, SP'nin entity ID'si ve ACS URL'si, bu yüzden aşağıdaki notlar çoğunlukla her konsolun bunları nerede tuttuğuyla ilgilidir. Hepsinde, assertion şifrelemesini kapalı bırakın.
- Microsoft Entra ID. Enterprise applications, New application, Create your own application (non-gallery). Single sign-on'da SAML seçin, ardından SP metadata'sını yükleyin veya Identifier (Entity ID) ve Reply URL'yi doldurun. Kullanıcı veya grup atayın, ve SAML Certificates içinde gösterilen App Federation Metadata Url'yi yükleyin.
- Okta. Applications, Create App Integration, SAML 2.0. Single sign-on URL, ACS URL'nizdir, “Use this for Recipient URL and Destination URL” işaretli olarak, ve Audience URI entity ID'nizdir. email, firstName ve lastName gibi attribute statements ekleyin, kişi veya grup atayın, ve Sign On sekmesinden Metadata URL'yi yükleyin.
- AD FS. Claims aware bir Relying Party Trust ekleyin ve SP metadata'sını içe aktarın. AD FS yalnızca https uç noktalarını kabul eder. Bir Name ID gönderen claim rules ekleyin, örneğin E-Mail-Addresses'in E-Mail Address olarak gönderilmesi, ardından E-Mail Address'in Name ID'ye dönüştürülmesi. IdP metadata'sı
https://<adfs-host>/FederationMetadata/2007-06/FederationMetadata.xmladresindedir. - Google Workspace. Admin console, Apps, Web and mobile apps, Add custom SAML app. IdP metadata'sını indirin, ACS URL'nizi ve entity ID'nizi girin, Name ID'yi seçin (örneğin birincil e-posta) ve uygulamayı kullanıcılarınız için açın.
- Keycloak. Client ID'si entity ID'niz olan bir SAML client oluşturun, veya SP metadata'sını içe aktarın. Keycloak varsayılan olarak tüm belgeyi imzalar, bu yüzden Sign assertions'ı da etkinleştirin. Client signature required açıksa,
SignAuthnRequests,SPCertificateveSPPrivateKey'i ayarlayın. IdP metadata'sıhttps://<host>/realms/<realm>/protocol/saml/descriptoradresindedir.
IdP ne olursa olsun, son adım aynıdır: metadata'sını LoadIdPMetadata'ya geçirin. Belge birden çok varlığı tanımladığında, ikinci parametre sizinkini seçer.
ProcessResponse Neyi Kontrol Eder
Bir SAML yanıtı imzalı bir XML belgesidir, ve iyi bilinen SAML güvenlik açıklarının çoğu, bir service provider'a imzalanan şeyden farklı bir şey okutmanın yollarıdır. Bir yanıt yalnızca aşağıdaki kontrollerin her biri geçtiğinde kabul edilir:
- IdP sertifikasına karşı imza. Yanıt yalnızca
IdPCertificatesiçindeki sertifikalarla doğrulanır. Mesajın içine gömülü bir sertifikaya hiçbir zaman güvenilmez, çünkü bir saldırgan da bir tane gömebilir. Varsayılan değer olanWantAssertionsSignedile, assertion kendi imzasını taşımalıdır. - Signature wrapping savunması. İmza, belgede ID'si benzersiz olan bir öğeye referans vermelidir, ve doğrulamadan sonra yalnızca imzalanan öğe okunur. İmzalı olanın yanına sokuşturulmuş imzasız bir assertion asla dikkate alınmaz.
- Tek bir assertion. Yanıt, doğrudan response'un altında tam olarak bir assertion içermelidir.
- Audience ve recipient. Audience,
EntityID'niz olmalı ve recipientAssertionConsumerServiceURL'niz olmalıdır, böylece başka bir uygulama için düzenlenmiş bir assertion reddedilir. - Zaman penceresi. NotBefore ve NotOnOrAfter, varsayılan olarak iki dakika olan
ClockSkewsaniyelik bir toleransla UTC'ye karşı kontrol edilir.MaxAssertionAgeayrıca bir assertion'ın ne kadar eski olabileceğini de sınırlayabilir. - InResponseTo. Yanıt, sakladığınız istek id'sini yanıtlamalıdır.
AllowIdPInitiated'ı ayarlamadığınız sürece, istenmeyen, IdP tarafından başlatılan yanıtlar reddedilir. - Tekrar oynatma (replay) önbelleği. Kabul edilen her assertion'ın ID'si süresi dolana kadar saklanır, böylece aynı yanıt iki kez POST edildiğinde reddedilir. Önbellek thread safe'dir ve bellekte bulunur. Birden çok sunucu oturum açmayı paylaştığında, ID'leri paylaşılan bir depoda tutmak için
DoAddToReplayCache'i override edin. - SHA-1 varsayılan olarak kapalı. RSA-SHA1 imzaları ve SHA-1 özetleri, hâlâ onlara ihtiyaç duyan bir IdP için
AllowSHA1'i ayarlamadığınız sürece reddedilir.
Ayrıştırıcı ayrıca DOCTYPE bildirimlerini reddeder, bu yüzden dış varlıklar (external entities) bulunmaz, ve belgenin boyutunu ve iç içe geçme derinliğini sınırlar. Issuer, yapılandırdığınız IdP olmalıdır. İlk başarısız kontrol doğrulamayı durdurur ve nedeni ErrorMessage'da bulunur: bunu loglayın, ve kullanıcıya basit bir “oturum açma başarısız” sayfası gösterin.
Hesap Olmadan Deneyin
SAML'in çalıştığını görmek için bir Entra ID tenant'ına ihtiyacınız yok. Mock SAML, mocksaml.com adresinde ücretsiz bir test identity provider'dır. Herhangi bir service provider'ı kabul eder ve audience ile ACS URL'sini AuthnRequest'ten alır, bu yüzden kaydedilecek hiçbir şey yoktur.
Demos\26.Authentication\03.SAML_ServiceProvider demosu, TsgcWebSocketHTTPServer üzerinde eksiksiz bir service provider'dır ve http://localhost:8090 üzerinde /login, /acs ve /metadata uç noktalarına sahiptir:
- Demoyu derleyin ve libcrypto-3.dll ile libssl-3.dll dosyalarını çalıştırılabilir dosyanın yanında tutun. Bunlar demo klasöründe bulunur, ve OpenSSL RSA imzalarını doğrular.
- Load IdP metadata'ya tıklayın. Varsayılan kaynak, mocksaml.com metadata URL'sidir.
- Start'a, ardından Open Browser'a tıklayın, ve oturum açma bağlantısını izleyin.
- mocksaml.com üzerinde, example.com alan adında herhangi bir kullanıcı adı ve herhangi bir şifre yazın.
- Tarayıcı ACS'ye geri döner, ve sayfa NameID'yi, SessionIndex'i ve id, email, firstName ve lastName niteliklerini gösterir.
Bu çalıştığında, http://localhost:8090/metadata'yı açın, gerçek IdP'nize kaydedin, demoda IdP metadata'sını yükleyin ve tekrar oturum açın. AD FS için, AD FS yalnızca https kabul ettiğinden, demoyu önce SSL ile çalıştırın.
Mevcut Sınırlamalar
- Şifrelenmiş assertion yok. Bir EncryptedAssertion veya şifrelenmiş bir NameID içeren yanıt reddedilir. IdP'de assertion şifrelemesini devre dışı bırakılmış bırakın. Assertion yine de imzalanır ve https üzerinden iletilir.
- Single Logout yok. SLO uygulanmamıştır. Uygulamanızın kendi oturumunu sonlandırabilmesi ve kendi çıkışını oluşturabilmesi için
SessionIndexdöndürülür.
Belgeler
Nereden Edinilir
TsgcSAMLServiceProvider, Delphi ve C++ Builder için sgcWebSockets'in Enterprise ve All-Access sürümlerine dahildir, ve aynı bileşen sgcWebSockets .NET'in de bir parçasıdır. Yalnızca kimlik doğrulamaya ihtiyacınız varsa, sgcAuth paketi bunu diğer oturum açma bileşenleriyle birlikte sunar. Unit adı sgcAuth_SAML_SP'dir, ve bileşeni bir forma yerleştirene kadar mevcut bir uygulamada hiçbir şey değişmez.
Sırada Ne Var
- Passkeys, SAML SSO, LDAP ve TOTP 2FA ile Delphi'de Giriş
- Delphi PKCE OAuth2
- PassKey'lerle Yetkilendirme
İzleyin
eSeGeCe kanalında “SAML single sign-on in Delphi with Entra ID, Okta and AD FS” başlıklı kısa bir video bulunuyor. Video, IDE'deki kodu ve mocksaml.com'a karşı demo ile yapılan canlı bir oturum açmayı gösteriyor.
Sorularınız, geri bildiriminiz mi var, veya identity provider'ınızı bağlarken yardıma mı ihtiyacınız var? Bizimle iletişime geçin. Kodu yazan kişilerden bir yanıt alacaksınız.
