Mischir 0 Posted July 14 Hello,. I am currently trying to read data from Salesforce via REST Api. There is a working example for Postman that I would like to implement for a project in Delphi (12) / ICS 9.2 The process is as follows: 1) Sending the certificate (PFX) + password to the host 2) The server sends back session cookies when the certificate has been verified. 3) Sending the client ID and secret together with the session cookies from the previous session 4) In the response header is a code "Location: xyz" 5) This code is then used to request a token. 6) You receive the token and can then make requests via the REST API. 1) and 2) work exactly the same as in Postman. My problem is that the session cookies do not seem to be transferred correctly and a new session is created under 3) and no code is sent. It must be the same session. If I copy the "Location code" from Postman and paste it into the Delphi application, 5) and 6) also work. I have also uploaded the logging in the attachment. I think this is the problem: 14:20:28:879 NSCB> New session created 14:20:28:879 000001CB1A118B70 CliNewSessionCB [000001CB1B664740] Reused: False The session is no longer used. In Postman there stands in the console : TLS: reused=true Here is my Code in Delphi. I have added a few lines of code for logging (Memo and ICSLogger) Thanks, if anyone finds a mistake or something is missing. Mike procedure TForm1.Button6Click(Sender: TObject); var HTTPRest: TSslHttpRest; SslContext: TSslContext; CookieManager: TIcsCookies; ResponseStream: TMemoryStream; ResponseHeaders: TStringList; Cookies: TStringList; Url: string; ResponseText: TStringList; i: Integer; errs: string; CookieHeader: string; begin if OpenDialog1.Execute then begin ED_PFX_Cert_Dir.text := OpenDialog1.FileName; // clear Memo mResult.Clear; try CookieManager := TIcsCookies.Create(self); SslContext := TSslContext.Create(self); HTTPRest := TSslHttpRest.Create(self); try ResponseStream := TMemoryStream.Create; ResponseHeaders := TStringList.Create; Cookies := TStringList.Create; ResponseText := TStringList.Create; SslContext.SSLVerifyPeer := true; SslContext.SslVerifyPeerModes := [SslVerifyMode_PEER]; SslContext.SslSessionCacheModes := SslContext.SslSessionCacheModes + [sslSESS_CACHE_CLIENT]; HTTPRest.SslContext := SslContext; HTTPRest.OnSslVerifyPeer := SslHttpRest1SslVerifyPeer; HTTPRest.CertVerMethod := CertVerWinStore; HTTPRest.RestCookies.AutoSave := true; // necessary, because I use cookiemamager? HTTPRest.Connection := 'keep-alive'; CookieManager.AutoSave := true; HTTPRest.RestCookies := CookieManager; // Sending certificate HTTPRest.SslCliCert.LoadFromFileEx(ED_PFX_Cert_Dir.text, croYes, croTry, Ed_PW_Cert.text, errs); if errs <> '' then mResult.Lines.AddStrings(errs); // Logger if Form1.Chb_logging.Checked then begin IcsLogger1.LogFileName := TPath.GetSharedDocumentsPath + PathDelim + 'ICSLogger.txt'; HTTPRest.IcsLogger := IcsLogger1; HTTPRest.DebugLevel := DebugHdr; end; // Set up SSL context with client certificate, necessary ??? SslContext.SslCertFile := ED_PFX_Cert_Dir.text; SslContext.SslPassPhrase := Ed_PW_Cert.text; HTTPRest.Url := ED_Url.text + '/nidp/app/login'; HTTPRest.RcvdStream := ResponseStream; HTTPRest.FollowRelocation := true; HTTPRest.SslSessCache := true; // First request to get session cookies try HTTPRest.Get; mResult.Lines.Add('HTTP GET request succeeded.'); except on E: Exception do begin mResult.Lines.Add('Error with connection: ' + E.Message); end; end; mResult.Lines.Add(Format('Response Code: %d', [HTTPRest.StatusCode])); mResult.Lines.Add(Format('Response Text: %s', [HTTPRest.ReasonPhrase])); // Extract cookies from response headers for i := 0 to HTTPRest.RcvdHeader.Count - 1 do begin if Pos('Set-Cookie:', HTTPRest.RcvdHeader[i]) > 0 then begin Cookies.Add(Copy(HTTPRest.RcvdHeader[i], Length('Set-Cookie: ') + 1, MaxInt)); end; end; // Output the response headers ResponseHeaders.text := HTTPRest.RcvdHeader.text; mResult.Lines.AddStrings(ResponseHeaders); // Output the response content ResponseStream.Position := 0; ResponseText.LoadFromStream(ResponseStream); // Prepare the next request Url := 'https://XYZ.com/nidp/oauth/nam/authz'; HTTPRest.Url := Url + '?response_type=code&client_id=' + ED_ClientID.text + '&redirect_uri=https://localhost:443&scope=apim'; ED_Request.text := HTTPRest.Url; // Add cookies to the header of the second request // Loop through all cookies for i := 0 to CookieManager.Count - 1 do begin // Construct the cookie header string if CookieHeader <> '' then CookieHeader := CookieHeader + '; '; CookieHeader := CookieHeader + CookieManager.Get1Cookie(i).CName + '=' + CookieManager.Get1Cookie(i).CValue; end; // Add the cookie header to the ExtraHeaders if CookieHeader <> '' then HTTPRest.ExtraHeaders.AddPair('Cookie', CookieHeader); mResult.Lines.Add('Cookies from first request:'); mResult.Lines.Add(CookieHeader); // Log the final URL and headers mResult.Lines.Add('Final request URL: ' + HTTPRest.Url); mResult.Lines.Add('Final request headers:'); mResult.Lines.AddStrings(HTTPRest.ExtraHeaders); HTTPRest.FollowRelocation := false; // Important ! // Second request , to get the "code" in HEADER "Location". try HTTPRest.Get; mResult.Lines.Add('HTTP GET2 request succeeded.'); mResult.Lines.Add(Format('Response Code: %d', [HTTPRest.StatusCode])); mResult.Lines.Add(Format('Response Text: %s', [HTTPRest.ReasonPhrase])); // Loop through the headers and show them for i := 0 to HTTPRest.RcvdHeader.Count - 1 do mResult.Lines.Add(HTTPRest.RcvdHeader[i]); // Output the response content ResponseStream.Position := 0; ResponseText.LoadFromStream(ResponseStream); mResult.Lines.AddStrings(ResponseText); except on E: Exception do begin mResult.Lines.Add('Error with connection: ' + E.Message); end; end; finally ResponseHeaders.Free; ResponseStream.Free; Cookies.Free; ResponseText.Free; end; finally SslContext.Free; CookieManager.Free; HTTPRest.Free; end; end; end; ICSLogger.txt Share this post Link to post
Angus Robertson 574 Posted July 14 Not sure why you wrote such complicated code, none of our examples look like that for TSslHttpRest, only the old THttpCli component . TSslHttpRest includes TSslContext, TIcsCookies and TMemoryStream so they are all redundant. The IcsLogger is also unnecessary, since the component has logging built in, using the OnHttpRestProg event. The OverbyteIcsSnippets sample has a function doHttpRestReqClick that makes a request with only a few lines of code. But before writing any code, I would use the OverbyteIcsHttpRestTst sample to test the URL and parameters. Angus Share this post Link to post
Mischir 0 Posted July 14 1 hour ago, Angus Robertson said: Not sure why you wrote such complicated code, none of our examples look like that for TSslHttpRest, only the old THttpCli component . TSslHttpRest includes TSslContext, TIcsCookies and TMemoryStream so they are all redundant. The IcsLogger is also unnecessary, since the component has logging built in, using the OnHttpRestProg event. The OverbyteIcsSnippets sample has a function doHttpRestReqClick that makes a request with only a few lines of code. But before writing any code, I would use the OverbyteIcsHttpRestTst sample to test the URL and parameters. Angus Hi Angus, Thanks for the tip! You saved my day 🙂 I used the code snippet from the OverbyteIcsSnippets doHttpRestReqClick and customized it a bit and it all works... and with just a few lines of code! Thanks for the quick support Regards, Mike Share this post Link to post