1
votes

I'm trying to send response back to servers requesting digest access authentication

  ....
  FResponseHeader.Text := FResponseText;// received header.
  FResponseHeader.ProcessHeaders;
   ....
  WriteLn(FResponseHeader.WWWAuthenticate); //WWW-Authenticate: Digest realm="xxxx.com", nonce="fq1uvocyzvr17e6a5syproazd5phwdvhvlc5", stale=false, algorithm=MD5, qop="auth"
  LIdAuthentication := TIdDigestAuthentication.Create;
  try
    LIdAuthentication.Username := FUser;
    LIdAuthentication.Password := FPass;
    LIdAuthentication.Uri      := FURI;
    LIdAuthentication.Method   := GetMsgTypeString(FResponseHeader.RequestMethods);
    LIdAuthentication.Params.Values['Authorization'] := FResponseHeader.WWWAuthenticate;
    LIdAuthentication.AuthParams.AddValue('Digest', FResponseHeader.WWWAuthenticate);
    for I := 0 to LIdAuthentication.Steps do
      LIdAuthentication.Next;
    Result := LIdAuthentication.Authentication;
  finally
    LIdAuthentication.Free;
  end;

I got 401 from the server.

What is the correct way to create the Authorization Header ?

1

1 Answers

3
votes

TIdDigestAuthentication (and other TIdAuthentication-derived classes) are intended to be used with TIdHTTP, not standalone.

If you are using TIdHTTP to communicate with a server, you do not need to manage Digest authentication manually at all. If the server requests Digest in its WWW-Authenticate header, and if IdAuthenticationDigest (or IdAllAuthentications) is in your uses clause, then TIdHTTP will automatically send a Digest response for you. The only thing you have to concern yourself with doing is:

  • set the TIdHTTP.Request.Username and TIdHTTP.Request.Password properties for the initial authentication attempt.

  • set a TIdHTTP.OnAuthorization event handler to handle the possibility of the server rejecting the current Username/Password so you can supply new values for retry, optionally after prompting the user.

  • optionally set a TIdHTTP.OnSelectProxyAuthorization event handler to choose which authentication scheme to use if multiple schemes are requested by the server, and/or if you want to control which scheme takes priority over others.

For example:

uses
  ..., IdHTTP, IdAuthenticationDigest;

...

IdHTTP1.OnAuthorization := AuthRequested;
IdHTTP1.Request.Username := ...; // initial username
IdHTTP1.Request.Password := ...; // initial password
IdHTTP1.Get(...);

...

procedure TMyClass.AuthRequested(Sender: TObject; Authentication: TIdAuthentication; var Handled: Boolean);
begin
  if (new credentials are available) then
  begin
    Authentication.Username := ...; // new username
    Authentication.Password := ...; // new password
    Handled := True;
  end else
    Handled := False;
end;

That being said, if you want to use TIdDigestAuthentication standalone, then you should use it similarly to how TIdHTTP uses it, eg:

LIdAuthentication := TIdDigestAuthentication.Create;
try
  LIdAuthentication.SetRequest(FGetMsgTypeString(FResponseHeader.RequestMethods), FURI);
  LIdAuthentication.Username := FUser;
  LIdAuthentication.Password := FPass;
  LIdAuthentication.Params.Values['Authorization'] := LIdAuthentication.Authentication;
  LIdAuthentication.AuthParams := FResponseHeader.WWWAuthenticate; // assuming WWWAuthenticate is a TIdHeaderList...

  repeat
    case LIdAuthentication.Next of
      wnAskTheProgram:
      begin
        // set LIdAuthentication.Username and LIdAuthentication.Password to new credentials to retry...
      end;

      wnDoRequest:
      begin
        // send new request with LIdAuthentication.Authentication in the 'Authorization' header...
        Result := LIdAuthentication.Authentication;
        Exit;
      end;

      wnFail:
      begin
        // error handling ...
        Result := '';
        Exit;
      end;
    end;
  until False;
finally
  LIdAuthentication.Free;
end;