Skip navigation links

Package com.pingidentity.pa.sdk.plugins

The PingAccess Plugin Framework

See: Description

Package com.pingidentity.pa.sdk.plugins Description

The PingAccess Plugin Framework

The PingAccess Addon SDK provides a framework to extend and customize product functionality using plugins. Plugins implement Service Provider Interface (SPIs) defined by the SDK. There are two categories of SPIs exposed by the SDK: configurable plugin interfaces and singleton plugin interfaces.

Configurable Plugins

A configurable plugin is a plugin that supports configuration and management by an administrator via the PingAccess Administrative API. These plugins describe the form of their configuration to PingAccess. PingAccess uses this information to present a uniform configuration interface to users of the PingAccess Administrative API.

Available configurable plugins

Implementing and installing a configurable plugin

The following generic steps are used to implement and install a configurable plugin. More information about implementing a specific plugin can be found in the documentation for each plugin.

Responsibilities of a configurable plugin

Describing the expected schema for plugin configuration

The PingAccess UI is built on its Administrative APIs. The UI for a plugin is driven from a GET request to the descriptor endpoint for the corresponding SPI, such as /rules/descriptors for RuleInterceptors. That endpoint is populated by interrogating the installed plugins and calling their DescribesUIConfigurable.getConfigurationFields() methods, defined by DescribesUIConfigurable.

PingAccess expects that the ConfigurationFields provided by the plugin describe the form of configuration data that can be mapped to a PluginConfiguration instance.

Validating and accepting configuration defined by an administrator

PingAccess maps the plugin's JSON configuration, defined via the Administrative API, to a PluginConfiguration instance. The concrete type of the PluginConfiguration used by the plugin is defined by the plugin annotation's expectedConfiguration field. The base class, SimplePluginConfiguration, is provided to aid implementing the PluginConfiguration interface.

PingAccess uses Jackson for JSON serialization and deserialization. A plugin can use Jackson custom serializers and deserializers to perform custom JSON mapping to fields in its configuration class. If a plugin requires custom JSON mapping, it must provide both a deserializer and serializer to allow PingAccess to store and transfer the configuration as JSON.

The ConfigurablePlugin interface expects implementations of ConfigurablePlugin.getConfiguration() to return the PluginConfiguration passed via the ConfigurablePlugin.configure(com.pingidentity.pa.sdk.policy.PluginConfiguration) method.

Once the JSON configuration is mapped into a PluginConfiguration, PingAccess validates the configuration in two ordered steps:

  1. Passing the configuration instance to a Validator. Any ConstraintViolations found will be returned to the administrator via the API.
  2. If the Validator returns no validation errors, the configuration instance is passed to the ConfigurablePlugin.configure(com.pingidentity.pa.sdk.policy.PluginConfiguration) method.

Using javax.validation constraints is the preferred method for validating a PluginConfiguration instance. The field represented by a ConstraintViolation should reflect the name of the corresponding field in the JSON configuration. This allows the API to correlate validation messages with their corresponding field in the JSON configuration. An easy way to accomplish this is to apply a Constraint to a field. That field's name should match the name of the ConfigurationField used to describe the field in the configuration. See this tutorial for an example of using javax.validation constraints

Alternatively, plugins can throw a ConstraintViolationException from the ConfigurablePlugin.configure(com.pingidentity.pa.sdk.policy.PluginConfiguration) method. This is not preferred, but if the validation must be performed programmatically, the ConstraintViolations defined within that exception will be used by the API to correlate validation messages to their corresponding field in the JSON configuration. Since this is not the preferred approach, plugins that take this route must provide their own implementation of the ConstraintViolation class.

An example of the preferred validation approach:

 public class ValidationExample implements ConfigurablePlugin<ValidationExample.Configuration>
 {
     private Configuration configuration;

     @Override
     public void configure(Configuration configuration) throws ValidationException
     {
         this.configuration = configuration;

         // These assertions are guaranteed by the framework to always be true
         assert(configuration.getAttributeName() != null);
         assert(configuration.getAttributeName().length() > 0);
         assert(configuration.getAttributeName().length() <= 16);
         assert(configuration.getAttributeValue() != null);

     }

     @Override
     public Configuration getConfiguration()
     {
         return configuration;
     }

     static class Configuration extends SimplePluginConfiguration
     {
         @NotNull
         @Size(min = 1, max = 16, message = "Attribute name length must be between 1 and 16 characters")
         private String attributeName;

         @NotNull
         private String attributeValue;

         public String getAttributeName()
         {
             return attributeName;
         }

         public void setAttributeName(String attributeName)
         {
             this.attributeName = attributeName;
         }

         public String getAttributeValue()
         {
             return attributeValue;
         }

         public void setAttributeValue(String attributeValue)
         {
             this.attributeValue = attributeValue;
         }
     }
 }
 
 

Understanding the lifecycle of a configurable plugin

A configurable plugin and its implementation of PluginConfiguration can be instantiated for many reasons and at many times. The following describes the lifecycle actions that occur before the configurable plugin is considered ready for use:
  1. The configurable plugin implementation class is instantiated.
  2. The instance is provided to Spring for autowiring and post construct initialization. See PostConstruct. The ordering of these operations is unspecified.
  3. The plugin annotation on the implementation class of the configurable plugin is interrogated to determine which instance of PluginConfiguration will be instantiated.
  4. The instance of PluginConfiguration is instantiated.
  5. The instance is provided to Spring for autowiring and post construct initialization. See PostConstruct. The ordering of these operations is unspecified.
  6. PluginConfiguration.setName(String) is called
  7. PingAccess maps the incoming JSON configuration to the PluginConfiguration instance.
  8. The PluginConfiguration instance is passed to a Validator.
  9. ConfigurablePlugin.configure(com.pingidentity.pa.sdk.policy.PluginConfiguration) is called with the validated PluginConfiguration instance.

Asynchronous plugins

The SDK also provides the following asynchronous versions of the configurable plugins to facilitate using a HttpClient. These interfaces should only be implemented if the implementation requires use of a HttpClient. Implementations of the asynchronous configurable plugin interfaces are intended to only be used with HttpClient. They are not intended to be used for scheduling asynchronous tasks. As a result, implementations should avoid using the following methods in CompletableFuture:

Singleton Plugins

A singleton plugin is instantiated once by PingAccess, during PingAccess startup.

Available singleton plugins

Implementing and installing a singleton plugin

The following generic steps are used to implement and install a singleton plugin. More information about implementing a specific plugin can be found in the documentation for each plugin.
See Also:
Java's ServiceLoader, Extensible applications and SPI, Wikipedia on SPIs
Skip navigation links

Copyright 2019 Ping Identity Corp. All rights reserved.