getting Basic Authentication parameters

In moving my REST server to XData I have many service contracts but only one that requires Basic Authentication, my Login logic. The client is sending the encoded information in the header, but I don't understand what I have to do in XData to get those parameters. I have included the BASIC Authentication middleware, but don't know where the Username and Password are.

Sparkle Basic Auth Middleware will expect you to pass a TAuthenticateBasicProc as parameter for it's Create constructor. The middleware will give you user-id and password and you are supposed to give it back an IUserIdentity instance --or-- nil if not autorized.

You may also have a look at BasicAuth demo in XData install folder.

Regards,

1 Like

On Sparkle Basic Auth, there is also an OnAuthenticate event as another way to go.

1 Like

I am not using Sparkle as a server, but rather I am using XDataServer. I only use the Sparkle Dispatcher

Yes. I got it. Basic Auth Middleware is from Sparkle. Anyway, for a XData RAD (component) aproach have a look at XData BasicAuth Demo. It shows how to use TSparkleBasicAuthMiddleware component Authenticate event handler :)

1 Like

Here is what I did. In the OnAuthenticate event for XData Server:

procedure TServerContainer.XDataServerBasicauthAuthenticate(Sender: TObject;
const UserName, Password: string; var User: IUserIdentity);
begin
if UserName <> '' then
begin
User := TUserIdentity.Create;
User.Claims.AddOrSet('username', UserName);
User.Claims.AddOrSet('password', Password);
end;
end;

Then in my service contract I access the information via:
sUserName := TXDataOperationContext.Current.Request.User.Claims.Find('username').AsString;
sPassword := TXDataOperationContext.Current.Request.User.Claims.Find('password').AsString;

Is this OK? Is there any significant overhead in having the Basic Auth Middleware active for all the other service contracts that don't send a username or password?

1 Like

Your code is ok and should work. But if you only have basic authentication in a single method, and since Basic Authentication is rather really simple, maybe it would be easier that in your Login method you just retrieve the basic authentication yourself, instead of using the middleware.

You can even copy/paste the code from TBasicAuthMiddleware.ProcessRequest and adapt to your needs.

    Auth := Context.Request.Headers.Get('authorization');
    if (Auth <> '') and SameText('Basic ', Copy(Auth, 1, 6)) then
    begin
      Auth := TEncoding.UTF8.GetString(TSparkleUtils.DecodeBase64(Copy(Auth, 7, MaxInt)));
      P := Pos(':', Auth);
      if P > 0 then
      begin
        UserName := Copy(Auth, 1, P - 1);
        Password := Copy(Auth, P + 1, MaxInt);
      end;
    end;
2 Likes

Yes, your code is fine. I just would not set/keep the password on user claims. You should validate the username/password on XDataServerBasicauthAuthenticate and create TUserIdentity only if user is authorized.

Your services (probably) will not need to have any knowledge of the user password.

If you are setting the password in user clains to be able to validate the user on a service basis (each service may or may not do it's own validation) than Wagner's aproach it's probably best for you.

Regards

1 Like