3

I'm connecting to a web service using basic authentication using the following code:

var
  RIO: THTTPRIO;
begin
  RIO := THTTPRIO.Create(nil);

  EndPoint := GetWebServicePort(True, '', RIO);

  RIO.HTTPWebNode.UserName := 'xxxx';
  RIO.HTTPWebNode.Password := 'yyyy';
...
end;

If the username and password are correct, everything works fine. However, if they are not correct, a Windows dialog pops up requesting the correct credentials. Instead of the dialog I need to catch the error.

enter image description here

How do I stop the dialog popping up? I've searched and found a couple of results (Link 1, Link 2), but neither seems offer a real solution.

Community
  • 1
  • 1
norgepaul
  • 6,013
  • 4
  • 43
  • 76
  • This is an old unsolved bug in THttpRio component. Use instead Indy – RBA Feb 23 '15 at 13:13
  • 3
    This is because the web service implementation in Delphi uses the "wrong" Windows API - using WinInet instead of WinHTTP. As MSDN explicitly says (https://msdn.microsoft.com/en-us/library/windows/desktop/aa382925%28v=vs.85%29.aspx), "WinINet displays a user interface for some operations such as collecting user credentials. WinHTTP, however, handles these operations programmatically." It's also very dangerous because if you use it in a service, the service may "hang" waiting on user input that could never be entered because the dialog is not shown in any user accessible desktop. – LDS Feb 23 '15 at 13:22
  • Not sure if this is useful as I haven't tried myself and I am not sure it would halt the `Windows` dialog, but maybe the event handler `HTTPRIO.HTTPWebNode.OnWinInetError` can come in hand? You would need to check for the `HTTP_STATUS_PROXY_AUTH_REQ` error. – Guillem Vicens Feb 23 '15 at 13:31
  • Note that it looks like you can use WinHTTP with Delphi SOAP: see http://stackoverflow.com/questions/26911550/delphi-xe6-soap-built-with-use-indy-connecting-to-a-webservice-over-a-proxy – mjn Feb 23 '15 at 13:32
  • @mjn - Even after defining USE_INDY, the dialog still appears. – norgepaul Feb 23 '15 at 18:09

1 Answers1

1

To catch the error, you can use a HTTP client library, for example Indy TIdHTTP, to run a HTTP GET (or HEAD) request on the web service address first, and catch the exception which is thrown when user / password are wrong.

uses
  ... IdHTTP ...;

...
var
  HTTP: TIdHTTP;

ValidCredentials := False;
...    
HTTP.Request.Username := username;
HTTP.Request.Password := password;
HTTP.Request.BasicAuthentication := True;
try
  HTTP.Head(url);
  ValidCredentials := HTTP.ResponseCode = 200;
except
  on ... (some Indy exception) do
  begin
    // signal that username / password are incorrect
    ...
  end;
end;

if ValidCredentials then
begin
  // invoke Web Service ...
mjn
  • 36,362
  • 28
  • 176
  • 378
  • While this is a solution that will work, it feels like a bit of a hack. Do we need to precede each connection with the code above or do it once and hope that the account credentials don't change after the initial check? However, as none of the other options seem to work, this might be our only chance. Thanks mjn! – norgepaul Feb 23 '15 at 18:12