SAML Single Sign-On in Delphi met Entra ID, Okta en AD FS

· Componenten
SAML Single Sign-On in Delphi met Entra ID, Okta en AD FS

Vroeg of laat stelt een grote klant de vraag: kunnen onze medewerkers inloggen op jullie applicatie met hun bedrijfsaccount? Ze bedoelen niet nog een gebruikersnaam en wachtwoord. Ze bedoelen de Microsoft Entra ID-, Okta- of AD FS-login die ze al voor al het andere gebruiken, met hun eigen wachtwoordbeleid, hun eigen tweefactorauthenticatie en één plek om een account uit te schakelen op de dag dat iemand vertrekt.

Het antwoord dat hun identiteitsteam verwacht, is SAML 2.0. In het overzicht van de nieuwe loginonderdelen kreeg SAML één alinea. Dit bericht is de volledige flow: wat TsgcSAMLServiceProvider doet, de code van een loginpagina en een Assertion Consumer Service, hoe u uw applicatie registreert bij de gangbare identity providers, en hoe u dit alles vandaag nog test zonder ergens een account te hebben.

Hoe SAML-aanmelding werkt

Er zijn drie partijen bij betrokken. Uw applicatie is de service provider (SP). De directory van de klant is de identity provider (IdP). De browser draagt de berichten tussen beide over, zodat uw server en de IdP nooit rechtstreeks met elkaar communiceren.

  1. De gebruiker opent uw login-URL. Uw applicatie bouwt een AuthnRequest en stuurt de browser door naar de IdP.
  2. De IdP meldt de gebruiker aan, met welke wachtwoord-, MFA- of conditional-access-regels het bedrijf ook hanteert.
  3. De IdP antwoordt met een ondertekende SAMLResponse, en de browser post deze naar de Assertion Consumer Service (ACS)-URL.
  4. Uw applicatie valideert de respons en maakt een eigen sessie aan voor de gebruiker die daarin wordt genoemd.

Stap vier is waar SAML-implementaties fout gaan, en dat is precies het deel dat het component voor u doet.

De service provider, stap voor stap

TsgcSAMLServiceProvider is geen HTTP-server. Het bouwt en controleert de SAML-berichten, en u roept het aan vanuit de request handler van de server die uw applicatie al heeft, bijvoorbeeld een TsgcWebSocketHTTPServer of een TsgcHTTPServer.

Met EntityID, AssertionConsumerServiceURL en LoadIdPMetadata eenmalig ingesteld bij het opstarten, passen de loginpagina en de ACS in één request handler:

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 en CreateUserSession staan voor uw eigen code: een GUID, een thread safe lijst geïndexeerd op RelayState die elk aanvraag-id één keer uitgeeft, en de sessiecookie van uw applicatie. Attributen komen binnen als Name=Value-regels, dus oResult.Attributes.Values['email'] leest er één op naam. Entra ID benoemt ze met claim-URI's zoals http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress.

De RelayState valt niet onder de handtekening van de IdP. Gebruik hem als sleutel om uw eigen openstaande aanvraag te vinden, nooit als een URL waarnaar u ongecontroleerd doorstuurt.

Uw applicatie registreren bij de identity provider

GetMetadata geeft de metadata van de service provider terug: uw entity ID en uw ACS-URL met de HTTP-POST-binding. Serveer deze op een URL zoals /saml/metadata, of sla ze op in een bestand, en geef ze aan de IdP. Elke identity provider vraagt om dezelfde twee waarden, de entity ID van de SP en de ACS-URL, dus de onderstaande notities gaan vooral over waar elke console deze bewaart. Laat bij alle de versleuteling van assertions uitgeschakeld.

Welke IdP het ook is, de laatste stap is hetzelfde: geef de metadata door aan LoadIdPMetadata. Als het document meerdere entiteiten beschrijft, kiest de tweede parameter de uwe.

Wat ProcessResponse controleert

Een SAML-respons is een ondertekend XML-document, en de meeste bekende SAML-kwetsbaarheden zijn manieren om een service provider iets anders te laten lezen dan wat er is ondertekend. Een respons wordt alleen geaccepteerd als elk van deze controles slaagt:

De parser weigert ook DOCTYPE-declaraties, zodat er geen externe entiteiten zijn, en beperkt de grootte en nestingdiepte van het document. De issuer moet de door u geconfigureerde IdP zijn. De eerste mislukte controle stopt de validatie en de reden staat in ErrorMessage: log deze, en toon de gebruiker een eenvoudige “aanmelden mislukt”-pagina.

Probeer het zonder account

U hoeft geen Entra ID-tenant te hebben om SAML in actie te zien. Mock SAML is een gratis test-identity provider op mocksaml.com. Het accepteert elke service provider en haalt de audience en de ACS-URL uit de AuthnRequest, dus er is niets te registreren.

De demo Demos\26.Authentication\03.SAML_ServiceProvider is een volledige service provider op een TsgcWebSocketHTTPServer, met de endpoints /login, /acs en /metadata op http://localhost:8090:

  1. Bouw de demo en houd libcrypto-3.dll en libssl-3.dll naast het uitvoerbare bestand. Ze staan in de demomap, en OpenSSL verifieert de RSA-handtekeningen.
  2. Klik op Load IdP metadata. De standaardbron is de metadata-URL van mocksaml.com.
  3. Klik op Start, daarna op Open Browser, en volg de aanmeldlink.
  4. Typ op mocksaml.com een willekeurige gebruikersnaam op het domein example.com en een willekeurig wachtwoord.
  5. De browser keert terug naar de ACS, en de pagina toont de NameID, de SessionIndex en de attributen id, email, firstName en lastName.

Als dat werkt, open dan http://localhost:8090/metadata, registreer dit bij uw echte IdP, laad de IdP-metadata in de demo en meld u opnieuw aan. Voor AD FS voert u de demo eerst uit met SSL, omdat AD FS alleen https accepteert.

Huidige beperkingen

Documentatie

Waar u het kunt krijgen

TsgcSAMLServiceProvider zit in de edities Enterprise en All-Access van sgcWebSockets, voor Delphi en C++ Builder, en hetzelfde component maakt deel uit van sgcWebSockets .NET. Als u alleen authenticatie nodig heeft, biedt het sgcAuth-pakket het samen met de andere loginonderdelen. De unit is sgcAuth_SAML_SP, en er verandert niets in een bestaande applicatie totdat u het component op een form plaatst.

Lees verder

Bekijk het

Er is een korte video, “SAML single sign-on in Delphi with Entra ID, Okta and AD FS”, op het eSeGeCe-kanaal. Deze toont de code in de IDE en een live aanmelding met de demo tegen mocksaml.com.

Vragen, feedback of hulp bij het koppelen van uw identity provider? Neem contact op. U krijgt antwoord van de mensen die de code hebben geschreven.