Datasnap + ODAC. Passing DB credentials?

Discussion of open issues, suggestions and bugs regarding ODAC (Oracle Data Access Components) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
pacste
Posts: 4
Joined: Fri 10 Apr 2015 20:18

Datasnap + ODAC. Passing DB credentials?

Post by pacste » Fri 10 Apr 2015 20:44

I am trying to port an existing 2-tier project to a 3-tier technology, and Datasnap looks promising.
Now, the client must not have direct access to the Oracle DB (that is why I am looking for a 3-tier technology), but may have different DB credentials, so the Datasnap Server does not "know" the user and password for the TOraSession in advance.

Here is what I accomplished so far with my experiments:

Client Side
-DB Components...
-TOraDataSource
-TClientDataSet (Provider:OraProvider RemoteServer:DSProviderConnection)
-TSQLConnection (Driver: Datasnap)
-TDSProviderConnection (linked with SQLConnection and the remote Datasnap Server)

Server Side
-----Server Container Unit----
-TDSServer
-TDSServerClass

-----Server Methods Unit-------
-TOraProvider
-TOraQuery
-TOraSession

If I set the TOraSession by design the demo works, but I can't find a way to set the DB credentials from the client. TSQLConnection has a ServerConnection/Username/Password properties but they seem to work only with dbExpress.
Maybe some kind of RPC protocol?

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Datasnap + ODAC. Passing DB credentials?

Post by AlexP » Tue 14 Apr 2015 10:12

Hello,

For user authentication, you can use the TDSAuthenticationManager.OnUserAuthenticate event.

P.S. See an example of DataSnap application with our components in DAC Team's blog: http://blog.devart.com/using-dac-produc ... pment.html .

pacste
Posts: 4
Joined: Fri 10 Apr 2015 20:18

Re: Datasnap + ODAC. Passing DB credentials?

Post by pacste » Thu 16 Apr 2015 18:11

Hi AlexP, thank you for the useful link.
I tried to use the OnUserAuthenticate event, but I couldn't find a way to access the ServerMethods unit from there.

I think I have the same issue as

http://stackoverflow.com/questions/2864 ... -server-me

TDSAuthenticationManager is in the Server
OraSession is in ServerMethods

How do I make the two units communicate?

This code does not link

Code: Select all

void __fastcall TServerContainer1::DSAuthenticationManager1UserAuthenticate(TObject *Sender,
		  const UnicodeString Protocol, const UnicodeString Context, const UnicodeString User,
		  const UnicodeString Password, bool &valid, TStrings *UserRoles)

{
	ServerMethods1->OraSession1->Username=User;
	ServerMethods1->OraSession1->Password=Password;
	valid = true;
}

Code: Select all

[ilink32 Error] Error: Unresolved external '_ServerMethods1' referenced from C:\PROJECTS\TESTDATASNAP\WIN32\DEBUG\SERVERCONTAINERUNIT1.OBJ
From the devart blog post you linked me:
Enter the following code into the OnUserAuthenticate event:

ServerMethods.usp_check_user.ParamByName('a_username').AsString := User;
ServerMethods.usp_check_user.ParamByName('a_passwd').AsString := Password;
ServerMethods.usp_check_user.Execute;
valid := ServerMethods.usp_check_user.ParamByName('result').AsBoolean;
I can't figure out how to make it work, since the Server does not seem able to access ServerMethods components

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Datasnap + ODAC. Passing DB credentials?

Post by AlexP » Fri 17 Apr 2015 08:32

ServerMethods is a global variable in the ServerMethodsUnit1.cpp module (that you should assign by yourself)

Code: Select all

#include "ServerMethodsUnit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TServerMethods1 *ServerMethods1; //Add
//--------------------------------------------------------------------------
You should also add automatic creation of this object in the file project:

Code: Select all

Application->CreateForm(__classid(TServerContainer1), &ServerContainer1);
Application->CreateForm(__classid(TServerMethods1), &ServerMethods1); //Add

pacste
Posts: 4
Joined: Fri 10 Apr 2015 20:18

Re: Datasnap + ODAC. Passing DB credentials?

Post by pacste » Tue 05 May 2015 18:36

Hi Alex,
I did what you suggested, but it doesn't work. I was able to create a global ServerMethods variable, but it is useless because each session creates its own ServerMethods instance anyway. I can send you my test project if you want, it's tiny.

pacste
Posts: 4
Joined: Fri 10 Apr 2015 20:18

Re: Datasnap + ODAC. Passing DB credentials?

Post by pacste » Tue 05 May 2015 20:47

I ported the code in Pascal and I think I have found a solution:

ServerContainerUnit

Code: Select all

implementation
{$R *.dfm}

uses Winapi.Windows, ServerMethodsUnit1, Datasnap.DSProviderDataModuleAdapter,Datasnap.DataBkr;

threadvar
thread_username:string;
thread_password:string;

procedure TServerContainer1.DSServerClass1GetClass(
  DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
  PersistentClass := ServerMethodsUnit1.TServerMethods1;
end;

procedure TServerContainer1.DSServerClass1Prepare(DSPrepareEventObject: TDSPrepareEventObject);
var
  a:TDSProviderDataModuleAdapter;
  b:TServerMethods1;
begin
  a:=(DSPrepareEventObject.MethodInstance as TDSProviderDataModuleAdapter);
  b:=(a.ProviderDataModule as TServerMethods1);
  b.OraSession1.UserName := thread_username;
  b.OraSession1.Password := thread_password;
end;

procedure TServerContainer1.DSAuthenticationManager1UserAuthenticate(
  Sender: TObject; const Protocol, Context, User, Password: string;
  var valid: Boolean; UserRoles: TStrings);
begin
  thread_username:=User;
  thread_password:=Password;

  valid := True;
end;
Let me know if it can be improved. I am worried about the eventual race conditions on the two vars: what happens when two clients try to login at the same time?

AlexP
Devart Team
Posts: 5530
Joined: Tue 10 Aug 2010 11:35

Re: Datasnap + ODAC. Passing DB credentials?

Post by AlexP » Wed 06 May 2015 07:36

To implement such behavior, you should include the Pooling property of OraSesssion. In this case, a separate connection will be created for each user and placed to the connection pool. Otherwise, there will be only one connection, and users will always change.

Post Reply