#1 2013-11-13 12:59:33

nirnir
Member
Registered: 2013-11-11
Posts: 66

authentication against external server

I'm converting my datasnap application into mormot .
How do I perform the authentication against external mssql users table ?
At this stage I want to keep working with my existing users/roles tables .

Offline

#2 2013-11-13 16:51:04

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

Re: authentication against external server

You can write your own authentication class, descending from TSQLRestServerAuthentication.
Then call TSQLRestServer.AuthenticationRegister/AuthenticationUnregister to register them.

mORMot internals expects TSQLAuthUser/TSQLAuthGroup to be available, but not necessary as true DB tables.
In your class, you can create in-memory TSQLAuthUser instances mapping your existing users/roles table.

Offline

#3 2014-04-01 08:22:10

maEverest
Member
Registered: 2014-04-01
Posts: 1

Re: authentication against external server

I am new to mORMot framework. I have a project (proof of concept really) that is loosely based on your demo project 14 - using interface classes - no direct db access.
It implements a single class (at the moment) with a bunch of methods. It works fine with dummy user using TSQLRestServerAuthenticationNone
but I actually need to authenticate against a custom authentication provider (existing external system that I have a delphi class for already that works - just not with your framework as yet)

I tried creating a custom authentication by doing:

TSQLAuthUserESI = class(TSQLAuthUser)
<snip code - just a bunch of properties that are in addition to your std username and pwd and are needed for locating and connecting to the authentication server so Server, port , role , environment all are RawUTF8 except for port which is integer >

TSQLRestServerAuthenticationEsi = class(TSQLRestServerAuthenticationURI)
  protected
    class function ClientComputeSessionKey(Sender: TSQLRestClientURI; User: TSQLAuthUser): RawUTF8; override;
  public
    function RetrieveSession(Ctxt: TSQLRestServerURIContext): TAuthSession; override;
    function Auth(Ctxt: TSQLRestServerURIContext): boolean; override;
    class function ClientSignIn(Sender: TSQLRestClientURI; const aUserName, aPassword,aServer: RawUTF8;
                                 const aPort: integer; const sEnvironment, sRole: RawUTF8
                               ): RawUTF8; virtual;

    constructor Create(aServer: TSQLRestServer); override;
  end;

But In my implementation of the new auth class methods in a bunch of spots I am running up against issues accessing protected methods of your ancestor classes, because unlike your ones, my classes are not in the same pas unit as your base classes.

example:

class function TSQLRestServerAuthenticationEsi.ClientSignIn(
  Sender: TSQLRestClientURI; const aUserName, aPassword, aServer: RawUTF8;
  const aPort: integer; const sEnvironment, sRole: RawUTF8): RawUTF8;
var U: TSQLAuthUserESIJDE;
begin
  result := 'FAIL';
  if Sender=nil then exit;
  try
    Sender.SessionClose;  // **** Cannot access protected symbol TSQLRestClientURI.SessionClose
    U := TSQLAuthUserESIJDE.Create;
    try
      U.LogonName := trim(uppercase(aUserName));
      U.PasswordPlain := aPassword; // compute SHA256('salt'+aPassword);
      //etc  ...
      result := Sender.SessionCreate(self,U,ClientComputeSessionKey(Sender,U)); // ***** TSQLRestClientURI.SessionCreate protected method
      fServer.SessionCreate(User,Ctxt,Session); // ***** protected method ...
 

So I guess I have 2 questions ;-)
1) Am I even doing the right thing here trying to create my own auth and user classes or can I just avoid auth altogether and do it later after I get my class custom instance?

2)  If I am doing the right thing - how do I get it to work? If not how do I avoid the need for setuser call- if I remove it then I seem to be unable to get the instance of my class due to 403 error.

Some more info:
I am using sicPerSession life for the classes.

I can for example in a (non mormot) vcl delphi app do:

mycon := Tmycon.create();
MyCon.Server := 'someserver';
MyCon.user := 'someuser';
MyCon.pwd := 'somepwd';
MyCon.role :='somerole';
MyCon.Environment := 'someEnvironment';
...
if MyCon.connect then
  begin
    mycon.Dosomething(some params);
    mycon.dosomethingelse(some other params); 
  end;  
mycon.free;

I want one instance of my Tmycon class per client session plus some other classes of my own code that uses that instance of Tmycon to make further calls to mycon and process the results etc. prior to passing results back to the REST client. For performance each session should process in it's own thread. Tmycon is not talking to a traditional database but to a  special system exposed though an api via the tmycon component.

So I create the interface and server class that exposes the fn's I want (as per your demo proj 14). That class  (Tconnector) internally creates and uses a instance of my (non mormot) Tmycon class.
(so far very simple but will expand it ...)

But in my client code (depending what button the user selects etc. I need to call something like:

TSQLRestServerAuthenticationNone.ClientSetUser(Client,'User',''); // want to get rid of this bit - it is useless and confusing to other customers ...
Client.ServiceRegister([TypeInfo(IConnector)],sicPerSession)

if Client.Services['Connector'].Get(I) then
  begin
     if i.sigon('someserver',''someuser','somepwd',''somerole','someenvironment') then
       i.dosomething(someparams ...)  
  end

So I either
1) need a way to tell your system - I want a session but don't want to call ClientSetUser at all I just want it to allow anyone to start a session when the first Client.Services['Connector'].Get(I) is called (ie when teh contract get statement arrives at server
    I think this may be possible as some calls like getsessiontimestamp or synchronizetimestamp don't seem to require auth having being done at all ...
or

2) need a way to create a custom class so I can instead do:

if TSQLRestServerAuthenticationESI.sigon (Client,'someserver','someuser','somepwd','somerole','someenvironment') = 'SUCCESS' then ...  

   

We will provide a default delphi client using mormot but our customers will be using their own systems (not always delphi) to talk to my http server - so I need the rest calls to be as simple and few as possible they will be generating and processing the calls without the benefit or your framework on the client end in many cases ...   

Hope this makes sense ...

Last edited by maEverest (2014-04-02 01:40:41)

Offline

#4 2014-04-21 06:54:10

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

Re: authentication against external server

I'm a bit confused by your question... so many points at once!
Sorry for answering late...

You can in fact by-pass the authentication for method-based services.
See TSQLRestServer.ServiceMethodByPassAuthentication().

But there is no global by-pass for the whole authentication stack, so that you can have automated "light" sessions.

I suppose that you can create a TSQLRestServerAuthentication* class, associated with a dedicated method-based service, to create your own sessions.
I mean, you can create your own TSQLRestServerAuthentication*.Auth(Ctxt: TSQLRestServerURIContext): boolean method, expecting your own set of parameters.
The purpose is to create your own in-memory session information.
This is perfectly feasible I guess, but a bit low-level.
If you start from TSQLRestServerAuthenticationNone class, it is IMHO not so difficult.

Offline

Board footer

Powered by FluxBB