Datasnap authentication is pretty straightforward once you use the correct parameter names (explained in Delphi Datasnap Server User Authentication). The next problem is to be able to use those same credentials when using a FireDAC Database Connection. The answer seems to be implied in Most efficient way to pass SQL Login credentials to Delphi Datasnap servers? although "simply forwarded" doesn't really explain how to accomplish the code. Further, these credentials should be authenticated as the same credentials used to log on to the Datasnap server. This will prevent impersonation at the database level.
So far I haven't been able to discover any way to obtain the current Datasnap user credentials programmatically from within the Server Methods unit. For example, in a BeforeConnect event. The code I'm working on is a standalone server built with Delphi XE7 using a Session lifecycle.
Here is a description of the events that take place when connecting to a Datasnap server and requesting data:
Let me explain further:
By using a few ShowMessage instructions I can trace the flow of Datasnap as I connect and make a data request. Running the server under Test allows me to display the contents of the various parameters that accompany the events. Once set up, running a client that connects to the server and requests data results in the following:
Client Login Button
Server event OnUserAuthenticate
At this point, the connection is established although nothing else has taken place on the server. Most importantly, neither the ServerClass nor the ServerMethodsClass have been instantiated. There is no place that I can see to store authentication credentials.
Client GetData Button
Data is returned to client (At this time the database credentials are hard coded into the TFDConnection ConnectionDefinition just to get it to work.)
OnUserAuthorize presents Sender parameter with a nil value; also presented is a TDSAuthorizeEventObject that doesn't contain any references that I have been able to use to find the ServerMethods instance, and, finally, a parameter named Valid, a boolean value used to authorize the user.
Note that TDSAuthorizeEventObject contains a reference to TDSServerMethodUserEventObject that DOES contain the Username along with Roles, Authorized Roles and Denied Roles. However, so what? This brings me back to my original question: How do I communicate this to code in the ServerMethodsUnit?
After some time I stumbled on the exact methodology to do this in a white paper by Bob Swart. There are several methods that will enable you to persist information during a Datasnap session. These belong to TDSSessionManager.GetThreadSession and are GetData, PutData, RemoveData, HasData, GetObject, PutObject, RemoveObject and HasObject. These methods actually manage two dictionaries that are part of the Session. So for example, in the UserAuthentication event you might store the username as follows:
TDSSessionManager.GetThreadSession.PutData('entrykey', UserName);
Later, in a OnBeforeConnect event for a database connection, you can retrieve these values for use in the connection:
DBUserName := TDSessionManager.GetThreadSession.GetData('entrykey');
In practice I find the "object" forms of greater value but either form offers a powerful way to persist your own data for the life of a session without resorting to external media.