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
- Credential Dialogue presented (this is my code, not the property of TSQLConnection that gets it wrong.)
- Username and Password entered.
- Paremeters Placed in TSQLConnection.Params [DSAuthenticationPassword, DSAuthenticationUser]
- Set TSQLConnection.Connected := True
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
- Client opens two client datasets consecutively.
- Server DSServerClass1.Create. This apparently implies that the
ServerTransport recognizes the request as valid and proceeds to
create the necessary assets to handle the session. - ServerMethodsUnit3.Create. Somewhere buried in the DSServerClass there is a GetClass invocation that returns the name of the associated ServerMethodsClass. The named class is instantiated. Since the ServerMethodsClass ultimately descends from a TDataModule this implies property streaming as well.
- OnUserAuthorize (Apparently first dataset)
- OnUserAuthorize (Apparently second dataset)
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?