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.

uApplicationPrivileges.pas

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 : IHYVCLVisualPlugin;
  [...]
  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 IHYVCLVisualPlugin;
  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.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.

dmMainData.pas

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.

fLoginForm.pas

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:

Concepts Covered