#1 2018-12-12 17:30:23

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Error 403 using TSQLRestServerAuthenticationDefault

I'm going back and forth to mORMot from time to time, this time I need to develop a server for which I think mORMot (including the ORM and SQLite ) wold be a good fit, I did in the past a couple of servers with Interface based services using TSQLRestServerAuthenticationDefault ( no ORM ) which are running fine, I'm comparing the sources of all and failing to see what is causing the troubles when consuming the services with authentication, I think I'm missing something but can't see what it is, I hope someone here know the reason :

Server ( interface definition )

Interface

Types
  TResultadoRegistro  = (rrcExito, rrcYaExiste, rrcErrorDeBaseDeDatos);

  IClientes = interface(IInvokable)
    ['{1DFFC3D9-474E-4B15-B2D7-0B42BB42A608}']
    function RegistrarCliente( const datos: TCliente; out IdCliente: Int64): TResultadoRegistro;
  end;


initialization
  TInterfaceFactory.RegisterInterfaces([TypeInfo(IClientes)]);

// Concrete class

  TClientesAdmon = class(TInterfacedObject, IClientes)
  protected
    fRest: TSQLRestServerDB;
  public
    constructor Create( ORM: TSQLRestServerDB ); reintroduce;
    function RegistrarCliente( const datos: TCliente; out IdCliente: Int64): TResultadoRegistro;
  end; 

// ORM

  fModel               := CreateModel(fConfig.Root);
  fRest                := TMyRestServerClass.Create(fModel, fConfig.Conexion.DatabaseName, false);
  fRest.Model.Owner    := fRest;
  fRest.DB.Synchronous := smOff; 
  fRest.DB.LockingMode := lmExclusive;
  fRest.CreateMissingTables;     
  fRest.AuthenticationRegister(TSQLRestServerAuthenticationDefault);   //  <--- Register authentication causes troubles on client calls
  fRest.ServiceRegister(TClientesAdmon.Create(fRest),[TypeInfo(IClientes)]);

// HTTP Server

  ServidorHTTP := TSQLHttpServer.Create( config.Port, [TSQLRestServer(fRest)]);
  ServidorHTTP.AccessControlAllowOrigin := '*'; 

Client side

  Model := CreateModel( paramsSrv.root );
  result := TSQLHttpClient.Create( paramsSrv.Host, paramsSrv.Port, Model, https);
  TSQLRestServerAuthenticationDefault.ClientSetUser(apiClient, User, Pass);
  apiClient.ServiceDefine([IClientes],sicShared);  // <--  THIS LINE CAUSES THE ERROR 403

The error :

TServiceFactoryClient.Create(): IClientes interface or TSQLRestRoutingREST routing not supported by server [{'
'"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"
}]
{"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"}

If I don't use authentication then I can consume the services and everything runs smooth so it seems I could be missing a config or something ?

Offline

#2 2018-12-18 23:47:53

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

I did another test, and also I realized that my report is incomplete, the error ocurrs with a server compiled with Lazarus/FPC trunk ( FPC 3.3.1, Lazarus 2.1.0 )

My tests :

- Server compiled with Lazarus and client compiled with Lazarus -- ERROR 403
- Server compiled with Lazarus and client compiled with Delphi (XE3) -- ERROR 403
- Server compiled with Delphi (XE3) and client compiled with Delphi (XE3) -- SUCCESS
- Server compiled with Delphi (XE3) and client compiled with Lazarus -- SUCCESS

So as far as I have tested the problem is just when the server is compiled with Lazarus, but since I need this server running on a Linux server, Delphi is not an option because XE3 does not have a Linux compiler and I don't want to upgrade to the latest version, in fact we are getting away from Delphi.

Does anybody faced this problem already?  Any hints ?

Offline

#3 2018-12-19 08:42:52

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Error 403 using TSQLRestServerAuthenticationDefault

Why do you call AuthenticationRegister()?
The default authentication is always there by default.

Offline

#4 2018-12-19 17:39:22

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

Why do you call AuthenticationRegister()?

Reason number one, because on the two other projects I did it that way without any problems so far (the servers are compiled with Delphi and running on Windows), I already have other FPC compiled server running on Linux but there was no need for authentication on that project.

The default authentication is always there by default.

Mmm, then I have something else wrong because without AuthenticationRegister() anybody can do things like this on the browser :

http://localhost:4299/rootapi/?sql=SELECT%20RowId,%20LogonName,%20DisplayName%20FROM%20AuthUser

And get the data :

[{"ID":1,"LogonName":"Admin","DisplayName":"Admin"},{"ID":2,"LogonName":"Supervisor","DisplayName":"Supervisor"},{"ID":3,"LogonName":"User","DisplayName":"User"}]

I don't want that behavior

So I'm calling AuthenticationRegister() so the answer to such requests will be :

{
"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"
}

That is what I expect.

Tried without AuthenticationRegister() but then the ORM seems to be open in the wild again, to avoid calling AuthenticationRegister() I changed the aHandleUserAuthentication parameter on RestServer creation to True :

fRest := TMyRestServerClass.Create(fModel, fConfig.Conexion.DatabaseName, True);

But then I am where I started. The FPC compiled server is giving 403 on any call from the client and the Delphi one is working as I think it should, so if there is anything else I must be doing Could you please tell me what it is ? In any case I don't understand why the difference in behavior between the two compiled servers.

Last edited by moctes (2018-12-19 19:05:15)

Offline

#5 2018-12-20 16:50:02

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

Seems like nobody is using FPC with the default authentication on a setup like the one posted, I don't know what else to do, there are coworkers already suggesting doing project on another technology (you name it go, elixir, etc ) but I don't like abandoning projects halfway and also I have hope I can do this with FPC because is already working with Delphi, I can continue the development that way, but I'm not confident to go on because if I finish the work with delphi I won't be able to deploy to a Linux server (which is a must), so if anyone has tips, recommendations on how to get over this I'll be thankful.

Offline

#6 2018-12-20 18:18:08

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Error 403 using TSQLRestServerAuthenticationDefault

FPC with all authentication schemes (including default) are part of the regression tests (TestSQL3).
See TTestServiceOrientedArchitecture methods.

We also use FPC on production with no problem.

So the problem is probably in your code.
But it is difficult to find out what is wrong with what you wrote.

I guess this is due to your own use of AuthenticationRegister() + TSQLRestServerAuthenticationDefault.ClientSetUser().
Just don't use AuthenticationRegister() and call TSQLRestClientURI.SetUser().

At least, provide a ready-to-replicate test program as an external link (in a zip archive, or as gist or github, and copy & pasted within this forum).

Offline

#7 2018-12-21 01:31:33

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

Thank you AB, perhaps is a misunderstanding on my side of how authentication works, I put a minimum project on BitBucket; it is a stripped down project (in fact it really does nothing besides playing with authentication).

https://bitbucket.org/mocte/demo_mormotfpc/src/master/

The same project contains server and client code, I put a checkbox on it to enable authentication, I'm not using AuthenticationRegister(), just changing aHandleUserAuthentication parameter on RestServer creation, when this parameter si set to true, the register customer button fails, the same code compiled on Delphi runs fine (in my original project at least).

Offline

#8 2018-12-22 18:09:29

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

When stripping things out I left some custom paths on compiler options, I hope that is not a trouble for you, also compiled that demo on an older Lazarus trunk installation on Ubuntu 16 ( the checkbox is not visible there, don't know if the .lfm file format has changed ), I had the same results no joy consuming services from a TSQLRestServer created with the HandleUserAuthentication parameter set to TRUE.


*Edit: versions on Ubuntu - mORMot 1.18.3778 FTS3
  The SOA Tests all pass on Delphi/Lazarus Windows/Linux

  I realize I didn't posted the complete text of the error message, here it is :
 

TServiceFactoryClient.Create(): IClientes interface or TSQLRestRoutingREST routing not supported by server [{
"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"
}]
{
"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"
}

Offline

#9 2018-12-22 19:06:16

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Error 403 using TSQLRestServerAuthenticationDefault

Just looking at the sources: for FPC, due to lack of RTTI for record (introduced in Delphi 2010), you need
1) to define your records as packed
2) to register the record serialization as text (see the doc)

Offline

#10 2018-12-22 19:22:31

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

ab wrote:

1) to define your records as packed
2) to register the record serialization as text (see the doc)

Thank you AB but that it's not the problem, for the sake of the demo I deleted those lines ( I thought they weren't needed ).

My TCliente record is alreadey defined as packed and on my original project I have in the interface unit the following lines:

const
  __TCliente  = 'ID Int64 Nombre, Direccion RawUTF8';

initialization
Begin
  TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TCliente),__TCliente).Options := [soReadIgnoreUnknownFields,soWriteHumanReadable];
  TInterfaceFactory.RegisterInterfaces([TypeInfo(IClientes)]);
End;

Doesn't make any difference, I still got the very same error.

Last edited by moctes (2018-12-22 19:25:09)

Offline

#11 2018-12-23 17:40:29

AOG
Member
Registered: 2014-02-24
Posts: 490

Re: Error 403 using TSQLRestServerAuthenticationDefault

I have made some changes to your source, to be able to compile with Delphi and FPC under win32.
Result: I can fully reproduce your problem !
Delphi: 100% success.
FPC: your reported failure.
Will investigate

Offline

#12 2018-12-23 18:17:02

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

Thank you AOG !   I thought I was going crazy.

Offline

#13 2018-12-27 23:36:19

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

Hi AOG, I don't want to interrupt your holidays smile but I have to ask because I've had this thing on hold for some days.

Did you find some time to look for a possible solution? 

Would you advise me to continue the development with the Delphi compiler while the problem is solved for FPC ?  I mean if it is within your reach to solve it

Anything you can comment on will be useful for us.

Offline

#14 2018-12-28 08:53:22

AOG
Member
Registered: 2014-02-24
Posts: 490

Re: Error 403 using TSQLRestServerAuthenticationDefault

Please try my version of your sources.

For me, these work ... ;-)

https://github.com/LongDirtyAnimAlf/moctes

Offline

#15 2018-12-28 20:10:36

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

AOG wrote:

Please try my version of your sources.

For me, these work ... ;-)

https://github.com/LongDirtyAnimAlf/moctes

Thank you !

Your project ran without any error. So I compared the .pas files one by one in order to integrate your changes to my project and have them almost identical, didn't worked the error continued to appear no matter what would have changed, but I had left out from the comparison the .lpi file which had compiler options because I thought the problem was on my code, so as a last resort I patched my .lpi with yours and on the next build everything automagically worked, so the problem must be some compiler options.

How did I configured my project ?

1. Project - New project
2. Project - Project options
3. In compiler options I choose Create Debug and Release modes

Maybe the third step made some adjustments that affected the way mORMot works ?  I'll try to investigate further, just FTR iin case someone else is faced with this problem

Thank you again Alfred

Offline

#16 2018-12-29 00:25:58

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

My original project is working now, the solution was uncheck the following option :

Project Options - Compiler Options - Debugging - Trash variables (-gt)

Thank you all.

Offline

#17 2018-12-29 10:29:51

mpv
Member
From: Ukraine
Registered: 2012-03-24
Posts: 1,534
Website

Re: Error 403 using TSQLRestServerAuthenticationDefault

This means you are using uninitialized variables in your code (accessing to a var inside a function before variable is initialized)

Offline

#18 2018-12-29 16:24:59

moctes
Member
From: Mexico
Registered: 2013-05-11
Posts: 129

Re: Error 403 using TSQLRestServerAuthenticationDefault

mpv wrote:

This means you are using uninitialized variables in your code (accessing to a var inside a function before variable is initialized)

Well in the demo I posted there isn't much code, let's review the code which triggers the error (the implementacion of the interface) :

function TClientesAdmon.RegistrarCliente(const datos: TCliente; out IdCliente: Int64): TResRegistroCliente;
begin
  IdCliente := 1;
  result    := rrcExito;
end;

A const parameter which comes from outside, an out parameter which is returned as 1, and the result of the function which has his value assigned, I think there isn't much to look at here, the error that is obtained when calling the method is:

TServiceFactoryClient.Create(): IClientes interface or TSQLRestRoutingREST routing not supported by server [{
"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"
}]
{
"errorCode":403,
"errorText":"Authentication Failed: Invalid signature (0)"
}

Speaks of the interface and authentication, so we could review the relevant code involved on the creation of the server:

  fModel               := CreateModel(fParams.root);
  fRest                := TSQLRestServerDB.Create(fModel, fParams.archivoDB, fParams.enableAuth);
  fRest.Model.Owner    := fRest;
  fRest.DB.Synchronous := smOff;
  fRest.DB.LockingMode := lmExclusive;
  fRest.CreateMissingTables;
  fRest.ServiceRegister(TClientesAdmon.Create(fRest),[TypeInfo(IClientes)]);
  ServidorHTTP := TSQLHttpServer.Create( fParams.Port, [TSQLRestServer(fRest)]);
  ServidorHTTP.AccessControlAllowOrigin := '*';

The f* variables are private fields of the server class, the ServidorHTTP is public, I'm failing to see where could be an unitialized variable in my code, Alfred made some tweaks here and there to my code but it doesn't prevent the error, so if that is the case I couldn't find the source of it, the documentation I found of the -gt switch is:

Trash local variables. This writes a random value to local variables at procedure start. This can be used to detect uninitialized variables. The t can be specified multiple times

I believe I can compile safely without it, maybe there are places on mORMot code that fall into that case but that's something I can not say for sure.

*Edit: spelling

Last edited by moctes (2018-12-29 16:36:11)

Offline

Board footer

Powered by FluxBB