Use of TXDataServer Events

Hi,

I cannot get the events such as OnEntityGet to fire. JWT login is working fine. Do I still have to add listeners?

Thanks,

Ken

What are you trying to do?

I am currently using a legacy XData server with Web Core. I am in the process of recreating this to include the TXDataServer component which works fine. I now want to include authorization by using a JWT Token and testing with Swagger before changing my Web App.

I have added the CORS, JWT and Generic modules to the TXDataServer and set the XDataServerGeneric.OnRequest event as

procedure TServerContainer.XDataServerGenericRequest(Sender: TObject; Context: THttpServerContext;
  Next: THttpServerProc);
var
  LastSegment: string;
  UserGUID:TGUID;
begin
  LastSegment := '';
  if (Length(Context.Request.Uri.Segments) > 0) then
    LastSegment:=Context.Request.Uri.Segments[Length(Context.Request.Uri.Segments)-1];
  LastSegment:=LowerCase(LastSegment);
  if (Context.Request.User=nil) and (LastSegment<>'login') and (LastSegment<>'$model') and
    (not LastSegment.StartsWith('swagger')) then
  begin
    Context.Response.StatusCode := 401;
    Context.Response.ContentType := 'text/plain';
    Context.Response.Close(TEncoding.UTF8.GetBytes('You are not authorized to access this data!'));
  end
  else
    Next(Context);
end;

As I now think I can just use this for everything as my requirements are all access or nothing.

I can do the login and authorization of swagger fine now. My ownly question is if Context.Request.User is not nil am I guaranteed that it is always aan authorized one?

After the request passes through the JWT middleware, if User is nil it means that the JWT token was not sent. If it's not nil, it means a valid signed token was provided.

Note that such construction you are using is not needed anymore as now the JWT middleware provides the event OnForbidRequest. You can now set the JWT to reject any anonymous requests, but in the mentioned event you can fine tune and allow/forbid specific requests (like the ones that refer to Swagger endpoints).

Thanks Wagner. Is OnForbidRequest documented anywhere as I can't find it in either the XData or Sparkle documentation.

I managed to work this out. It's a much better mechanism thanks. Having some problems with displaying database images using an link. The only way I have found round this is in the OnForbidRequest to set Forbid to false if it's one of my image fields being downloaded. This works fine but is then a hole in the security. Is there a better way?

Just to follow up from here, if you're using a image link to reference an XData endpoint, this can be very handy as I indicated in the blog post. However, in such cases, it is the browser making the request on behalf of your application, so none of the credentials (JWT, etc.) are passed on to XData in this case. So the request can't be authenticated in the normal way.

That doesn't mean that it can't be authenticated though. Other parameters could be included in the same URL string that the endpoint could use to authenticate the request.

If you make a point of logging the valid JWTs that you've issued, into your database, you can perhaps pass a hash of the JWT as a parameter to your endpoint and see if there's a matching hash in your JWT table.

Or if you're logging the IP as well, you could check that the request is coming from an authorized IP. Or maybe both validate the IP and the JWT hash.

Or your app could encode or encrypt the URL request in a single-use sort of way so that anyone copying the URL and trying to access it again later would not be successful.

In the post, I think I mentioned that this link mechanism is very handy but ideally for images that aren't in need of this kind of protection, and also because of the performance implications. If you're transferring hundreds of images, this can result in a heavy load on the XData side - hence all the effort spent on caching mechanisms to avoid exactly this kind of overhead.

Regardless, lots of options, but it may come as a bit of a surprise to see that the browser will happily make requests on behalf of your app without any authorization information.

Thanks Andrew. I will probably look into adding an additional parameter. I've also tried retrieving the image directly from the database via an authenticated method which I would prefer but can seemt find a way of diisplaying them. They are already base64.

One way is to add the rest of the data uri to the base64 string if it isn’t there already and then supply that as the src parameter to an <img> element on the page.

Thanks, I have this working in combination with JWT now.

1 Like