Authentication and Login
Login and Authentication Overview
One of the key requirements of most multi-tier applications is to limit access to a specific group of authorized users, and possibly to apply different restrictions of access to different users accessing the server.
When writing real life business applications with Remoting SDK or Data Abstract, one important concern is security. Chances are that your middle-tier server is exposing sensitive data that you would not want any anonymous user on your local LAN (or worse, the entire Internet) to access or even modify. A login system is needed to ensure that only authorized users can access the data, and/or that these authorized users only get access to the subset of data they are allowed to access.
This topic describes the default, "best practices" login and user authentication system that is recommended for Remoting SDK applications that require user-level security. This system is built on top of the Remoting SDK architecture, so you can also use a different system or use the principles outlined here in different ways to better suit your particular needs.
Session Management & Authentication
By default, the instances of your Remoting SDK service are created without reference to a specific client, and subsequent calls into your server might be served by different instances. You cannot assume that field values from a previous call are still accessible when the next call from a client comes in. This is what makes Remoting SDK servers stateless and forms the foundation of proper scalability.
Sessions provide a means of storing client-specific information in a separate storage that is independent of the actual service instances processing the request. There could be a different instance for each call, or they might even be running on different physical servers in a server farm, but data is persisted between calls.
For authentication, a session is used to store the identity (and possibly details about the privileges) of the user as he logs in. This information is then available in subsequent data access calls. If no session or no valid login information is found in a data call (because the user did not authenticate correctly before), the request will be rejected immediately.
Login and the Service Base Classes
The service base classes (RemObjects.SDK.Server.Service in .NET and TRORemoteDataModule in Delphi) that are used as the base for your own service implementations already contain the necessary code to handle sessions for you. In particular, the Session indexer property wraps all session accesses, allowing you to store custom named values such as User ID or privileges in one call and retrieve them again in the next.
Also, the RequireSession property can be set to true to force all calls in a particular service to require an existing session - basically preventing any access to a particular service until a session has been established by talking to another service class (typically a specific Login service).
The Login Service
A login service is a secondary service implemented in your Remoting SDK server that is provided for the sole purpose of having clients log in (authenticate) and log out. Usually, this service will be implemented independently of the "real" services (which could be Data Abstract data services or standard Remoting SDK services exposing your custom business logic).
A typical login service will expose two methods, Login and Logout. The Login method will verify the authentication info received from the client (commonly a user name and password), create a session and fill it with information about the user (which could include the User ID, a list of privileges specific to the user, or any other custom information relevant to your real services). The Logout method will simply undo a previous login by destroying the session.
The specific details of how to handle authentication are of course entirely up to you. Login can be defined to receive a user name and password, use a shared key or any other system of uniquely identifying a user that you may find suitable. You may also use additional security measures, such as verifying the client's IP address against a list of approved addresses, to tighten security. Also, it is up to your design how to look up the actual user information. Depending on your needs, your server might for example use a single login specified in a local configuration file or obtain a list of valid users from a database table.
The key is that your Login method will create a session only if the login was successful.
Enforcing authenticated access in your "real" services can happen on several levels.
Firstly, setting the RequireSession property mentioned above to true will ensure that your service methods will only execute if a session has previously been established through login. This will function without the need of any custom code.
Secondly, you can either use the OnActivate event of your service or your actual method implementations to perform additional checks based on privileges stored in the session. For example, during login, you could store a flag indicating whether the user is an administrator or not, and reject certain actions based on this flag.
Automatic Login on the Client Side
On the client side, the Remoting SDK provides infrastructure to seamlessly integrate login and authentication.
The Client Channels provide special logic to trap this exception and fire an OnLoginNeeded event when this occurs, giving your client the chance to perform a login manually, and then retry the request. If the login is successful and the request succeeds at the second attempt, the entire login process will be transparent to your application - the code that initiated the original request will never know it failed and a login was required.
A typical implementation of the OnLoginNeeded event handler would be to show a login dialog to ask for username and password (possibly persisting this information locally, for future use), call the Login method on the server and then set the aRetry parameter of the event to true.
Note that all editions of Remoting SDK are prepared to handle the respective "session not found" exceptions from the other SKUs, so that this mechanism will work seamlessly between platforms.
Handling Session Timeouts
This entire process will occur both when an initial login for a newly connected client is needed and when a session on the server has timed out because the client has been idle for a given amount of time.
Depending on your specifications and the security needs for your client application, you might want to prompt to (re-)enter user name and password each time OnLoginNeeded is fired, or store the login information locally after it was first entered and silently call Login as needed so the user never notices his session on the server had timed out.
Design Time Login
The Remoting SDK IDE integration provides a default Design Time Login Dialog for this purpose. This dialog will obtain the list of services and methods available on the server and allow you to call any one (or more) methods to manually perform the necessary authentication:
From this dialog, you can select the login service and method (if you're using the default names provided by the template, the right items will be pre-selected for you), enter your login information and perform the login call to the server.
Once this is done, the IDE will re-attempt the original request, which, if your login was successful, will now succeed. As at runtime, your session will be maintained during design time, so for subsequent requests the login dialog will not reappear until your session has expired on the server.