The following sections provide a detailed description of the changes, organized by package. Where relevant, code examples show you how to port existing code to account for the changes in the SDK APIs.

Important: Because the SDK for PingAccess 6.1 uses Java 8 features, plugins built against the Java add-on SDK for PingAccess 6.1 or later must be built with JDK 8.

Prevent modification to request in response chain

Starting in PingAccess 6.1, any modifications made to a request or its header fields during response processing will now result in a warning log message and the modification operation being ignored. Previously, PingAccess would log a warning message about the modification but still allow the modification operation to complete.

Retrieving key pair and trusted certificate group configuration data

In the previous version of the SDK, a SDK plugin accessed the configuration data of a key pair or trusted certificate group configured using the administrative API by annotating a field in the plugin's PluginConfiguration class with a JsonDeserialize annotation, specifying the appropriate custom deserializer from the SDK.

public class Configuration extends SimplePluginConfiguration
{
   @JsonDeserialize(using = PrivateKeyDeserializer.class)   
    KeyStore.PrivateKeyEntry keyPair;

   @JsonDeserialize(using = TrustedCertificateGroupDeserializer.class)   
    Collection<X509Certificate> certificateGroup;
}

In the current version of the SDK, this mechanism has changed to be less error-prone as well as to provide access to more properties of the key pairs and trusted certificate groups. The previous configuration class should be ported to the following:

public class Configuration extends SimplePluginConfiguration
{
   KeyPairModel keyPair;

   TrustedCertificateGroupModel certificateGroup;
}

The KeyPairModel#getPrivateKeyEntry method provides access to the KeyStore.PrivateKeyEntry object for the corresponding key pair in the administrative configuration. The TrustedCertificateGroupModel#getCertificates method provides access to the Collection of X509Certificate objects in the corresponding trusted certificate group in the administrative configuration. Refer to the JavaDoc for each of these classes for more information.

Related to this change, the provided implementations of ConfigurationModelAccessor, PrivateKeyAccessor and TrustedCertificateGroupAccessor, have been updated to use these new classes. Both classes have also been moved to new packages. PrivateKeyAccessor has also been renamed to KeyPairAccessor.
Before PingAccess 5.0:
import com.pingidentity.pa.sdk.accessor.PrivateKeyAccessor;
import com.pingidentity.pa.sdk.accessor.TrustedCertificateGroupAccessor; 

// … class definition omitted ... 

private void invokePrivateKeyAccessorGet(
       PrivateKeyAccessor accessor,
       String id)
{
   KeyStore.PrivateKeyEntry keyPair = accessor.get(id);
} 
private void invokeTrustedCertificateGroupAccessorGet(
       TrustedCertificateGroupAccessor accessor,
       String id)
{
   Collection<X509Certificate> certificates = accessor.get(id);
}
After PingAccess 5.0:
import com.pingidentity.pa.sdk.accessor.certgroup.TrustedCertificateGroupModel;
import com.pingidentity.pa.sdk.accessor.keypair.KeyPairAccessor; 

// … class definition omitted ... 

private void invokePrivateKeyAccessorGet(
       KeyPairAccessor accessor,
       String id)
{
   KeyStore.PrivateKeyEntry keyPair = accessor.get(id)
                                              .map(KeyPairModel::getPrivateKeyEntry)
                                              .orElse(null);
} 

private void invokeTrustedCertificateGroupAccessorGet(
       TrustedCertificateGroupAccessor accessor,
       String id)
{
   Collection<X509Certificate> certificates = accessor.get(id)
                   .map(TrustedCertificateGroupModel::getCertificates)
                   .orElse(null);
}

Changes to validation of PluginConfiguration instances

In the previous version of the SDK, the ConfigurablePlugin#configure method was invoked and passed a PluginConfiguration instance. The ConfigurablePlugin was expected to assign the specified PluginConfiguration instance to a field annotated with the javax.validation.Valid annotation. After the configure method returned, PingAccess passed the ConfigurablePlugin instance to a javax.validation.Validator for further validation.

If setup correctly, this logic allows javax.validation.Constraint annotations to declare the validation to be applied to fields in a PluginConfiguration implementation, ensuring the configuration is valid as well as providing validation error message to PingAccess to provide to administrators using the Administrative API or UI.

However, if the ConfigurablePlugin#configure method needed to post-process the specified PluginConfiguration instance, the method needed to duplicate all the validation declared on the fields of the PluginConfiguration.

To remove the need for this duplication of validation logic, PingAccess now validates the PluginConfiguration instance with a javax.validation.Validator prior to passing the instance to the ConfigurablePlugin#configure method.

Further, the ConfigurablePlugin no longer needs to annotate the field used to hold the PluginConfiguration instance. The field is still necessary to implement the ConfigurablePlugin#getConfiguration method.

The following example ConfigurablePlugin implementation demonstrates this change.

public class ValidationExample
       implements ConfigurablePlugin<ValidationExample.Configuration>
{
   // @Valid annotation no longer required
   private Configuration configuration;

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

       // With the previous version of the SDK, these assertions were not
       // guaranteed to be true, despite the javax.validation.Constraint
       // annotations enforcing these conditions.
       //
       // In the current version of the SDK, these assertions are guaranteed
       // to be true because they are enforced by the javax.validation.Constraint
       // annotations on the fields in the PluginConfiguration class, and the
       // PluginConfiguration validation is performed before invoking the
       // configure method.
       //
       // The end result is that plugins can remove duplicated validation
       // logic from the configure method if further post-processing of the
       // configuration needs to be performed.
       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;
       }
   }
}