Security Sample (Delphi)
The Security sample demonstrates Hydra's ability to perform security checks on plugins. The security is fully customizable and allows you to limit actions that are exposed by the plugin according to your own security logic.
Examine the Plugin
The Security Module plugin is a VCL plugin that shows a list box and provides the ability to add and delete items from this box. If you need more information on how to create a VCL plugin, please refer to this article.
Basically, the code of the plugin performs simple tasks like adding and deleting items from the list box. However, there are some key points:
Let's take a look at the plugin registration code:
initialization THYPluginFactory.Create(HInstance, 'MyFirstSecurePlugin', Create_VisualPlugin, TVisualPlugin, 1, 0, priv_View);
This code registers a plugin in the module, please take a look at the last line: priv_View is a custom string constant that sets the security token required by this plugin. The host will perform a check, and if the current user doesn't have the required privilege, it won't create an instance of the plugin.
The second important thing is the action list:
It holds a list of actions that will be exposed to the host application. Take a loot at the RequiredPrivilage property, it also holds a custom token that defines what security privilege is required to run this action.
Both plugin and host share the same uApplicationPrivileges.pas unit. It holds the definition of our custom security tokens:
const priv_Add = 'ADD'; priv_Delete = 'DELETE'; priv_View = 'VIEW';
As you can see, they are simple string constants that define tokens for specific actions.
Examine the Host
The host is a Delphi application that is able to show our plugin and control the security options. For more information on how to create a Delphi VCL host application, please refer to this article.
Let's take a look at the major parts:
type THostForm = class(TForm) [...] ModuleManager: THYModuleManager; private fEditForm : IHYVisualPlugin; [...] end; procedure THostForm.FormShow(Sender: TObject); var intfinstance : IInterface; begin // The names of the modules to load were assigned at design-time // See property ModuleManager.ModulesToLoad ModuleManager.LoadModules; ModuleManager.CreateInstance('MyFirstSecurePlugin', intfinstance); fEditForm := intfinstance as IHYVisualPlugin; fEditForm.ShowParented(MainPanel); end;
As you can see, the main form is a regular Delphi VCL form, and can be used in the exact same way as any regular form. There are two key items here:
- ModuleManager: THYModuleManager - Key component that manages modules
- fEditForm : IHYVisualPlugin - Reference to the plugin instance
- ModuleManager.LoadModules - This method allows you to load all plugins that were specified in the ModuleManager.ModulesToLoad list. Module manager will automatically detect the type of a module and will use the appropriate method. It also provides a couple of methods for module loading, such as loading from a list of file names or loading using a search pattern.
- HYModuleManager1.CreateInstance - This method will create an instance of the plugin with the specified name and assign this instance to the intfinstance variable that we defined above.
- fEditForm.ShowParented(MainPanel) - This method shows the visual plugin in a specified parent control. Instead of @@@combination CreateInstance/Instance.ShowParented@@@ you can use ModuleManager.CreateVisualPlugin method that will do the same.
The next thing is the user profile:
This property points to the THYUserProfile object that is located in the data module; let's take a look at it.
This data module holds the THYUserProfile component and provides code that processes user login; let's take a look at this method:
procedure TMainData.UserProfileProcessLogin(Sender: THYUserProfile; const aUserID, aPassword: String; var LoginResult: THYLoginResult); begin LoginResult := lrFailed; // Performs the login if ( (SameText(aUserID, 'john') and SameText(aPassword, 'smith')) or (SameText(aUserID, 'lara') and SameText(aPassword, 'croft')) or (SameText(aUserID, 'joe') and SameText(aPassword, 'hills')) or (SameText(aUserID, 'carlo') and SameText(aPassword, 'lean')) ) then LoginResult := lrOK; // Assigns the right privileges if (LoginResult=lrOK) then begin if SameText(aUserID, 'john') then Sender.SetPrivilegeList([priv_View, priv_Add, priv_Delete]) else if SameText(aUserID, 'lara') then Sender.SetPrivilegeList([priv_View, priv_Add]) else if SameText(aUserID, 'joe') then Sender.SetPrivilegeList([priv_View]) else Sender.SetPrivilegeList() end; end;
This method can be split in two parts. First, it checks user login details; for this sample we used a predefined login/password, but in real life applications, this can be as complicated as you want it to be. The second part is setting a privileges list for a specific user; as you can see, we use the same string constants as we've used in the plugin.
The last part of the host application is a login form. This form provides our predefined login/password details:
This form also implements the IHYLoginForm interface:
TLoginForm = class(TForm, IHYLoginForm) [...] protected function GetUserID : string; procedure SetUserID(Value : string); function GetPassword : string; procedure SetPassword(Value : string); [...] end;
So this form can be used by the THYUserProfile class when it needs login details:
procedure TMainData.DoLogin; begin UserProfile.Login(TLoginForm); end;
Putting It All Together
Now that we've examined all major parts of the sample, we can build both plugin and host. And after we launch the sample, we should get following results: