PingAccess

Integrate with third-party services

The Add-on SDK includes the ability for a custom plugin to integrate with external, third-party services using HTTP.

This section provides a high-level overview of utilizing this functionality from a custom plugin:

Obtaining the HTTP client instance

PingAccess provides access to a HTTP client utility interface, HttpClient, through dependency injection. Plugins are expected to obtain an instance of this interface using an approach like the following.

public class DocumentationPlugin // interfaces and base classes omitted for brevity
{
    private HttpClient httpClient;

    // ... other code omitted ...

    @Inject
    public void setHttpClient(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    // ... other code omitted ...
}

Obtaining a handle to a third-party service

Given a HttpClient instance, a plugin will also need a handle to a third-party service to make an outbound HTTP call to the service represented by the Third-Party Service administrative configuration object. This handle is an instance of the ThirdPartyServiceModel class and is specified to the HttpClient in its send method.

There are two different ways to obtain a ThirdPartyServiceModel instance:

Administrator-configured third-party services

The PingAccess Administrative UI and application programming interface (API) allow administrators to define the communication configuration for an external service by defining a third-party service. These configuration objects can then be associated with custom plugins through their configuration.

To enable a plugin’s configuration to reference a third-party service, it should define a field in the configuration with the type of ThirdPartyServiceModel.

    private static class Configuration extends SimplePluginConfiguration
    {
        // ... other code omitted ...

        @UIElement(order = 30,
                type = ConfigurationType.SELECT,
                label = "Risk Authorization Service",
                modelAccessor = ThirdPartyServiceAccessor.class,
                required = true)
        @NotNull
        private ThirdPartyServiceModel riskAuthzService;

        // ... other code omitted ...

        public ThirdPartyServiceModel getRiskAuthzService()
        {
            return riskAuthzService;
        }

        public void setRiskAuthzService(ThirdPartyServiceModel riskAuthzService)
        {
            this.riskAuthzService = riskAuthzService;
        }
    }

The important items in this example:

  • The modelAccessor attribute of the UIElement must be set to ThirdPartyServiceAccessor.

  • The field in the plugin configuration class must be of type ThirdPartyServiceModel.

Third-party services for the OAuth authorization server and OIDC provider

In addition to providing a way for an administrator to configure a plugin to use an arbitrary third-party service, PingAccess allows a plugin to use a third-party service that represents the OAuth Authorization Server or OpenID Connect (OIDC) provider. The benefit of leveraging this functionality is that a plugin can require access to either of these services without requiring the administrator to configure the plugin to use those services.

Similar to the previous section, the plugin obtains a ThirdPartyServiceModel instance that is a handle to the OAuth Authorization Server or OIDC provider by indicating this requirement in its plugin configuration class. However, the mechanism is a bit different, as shown in the following example.

    private static class Configuration extends SimplePluginConfiguration
    {
        // ... other code omitted ...

        private ThirdPartyServiceModel oidcProvider;

        // ... other code omitted ...

        public ThirdPartyServiceModel getOidcProvider()
        {
            return oidcProvider;
        }

        @Inject
        @OidcProvider
        public void setOidcProvider(ThirdPartyServiceModel oidcProvider)
        {
            this.oidcProvider = oidcProvider;
        }
    }

The setter for the oidcProvider field is annotated with the @OidcProvider annotation.

If the @OidcProvider annotation includes a parameter, that parameter specifies a required endpoint defined by the OIDC provider metadata of the current token provider. When the plugin is instantiated, the validation for the @OidcProvider parameter will pass only if the specified endpoint is a valid HTTP Uniform Resource Identifier (URI) in the OIDC provider metadata. For example, the following annotation will require the backchannel_authentication URI.

@OidcProvider(“backchannel_authentication”)

Making a HTTP call to a third-party service

With an instance of HttpClient and an instance of ThirdPartyServiceModel in hand, a plugin can make a HTTP call to the external service represented by the ThirdPartyServiceModel. Here is an example method that makes a GET request to a resource on the external service with a path of /data and a query string of page=1.

private static CompletionStage<ClientResponse> sendRequest(HttpClient httpClient,
                                                           ThirdPartyServiceModel model)
{
    Headers headers = ClientRequest.createHeaders();
    headers.setAccept(Collections.singletonList("application/json"));

    ClientRequest request = new ClientRequest(Method.GET,
                                              "/data?page=1",
                                              headers);

    return httpClient.send(request, model);
}

The result of the HttpClient send method is a CompletionStage. A CompletionStage is returned because PingAccess is performing the HTTP call asynchronously and as a result, handling of the result of the call needs to be performed by callbacks registered with the CompletionStage.

You can use the getRequestUri() method to stand in for the endpoint. This can be useful if the endpoint is not known during development.

    ClientRequest request = new ClientRequest(Method.GET,
                                              model.getRequestUri().get(),
                                              headers);

The RequestUri is set by the @OidcProvider("RequestUri") annotation, and is unset if the @OidcProvider("RequestUri") annotation is not present.

For a more complete example of using the HttpClient to make an external HTTP call, see the sample SDK plugins packaged with the PingAccess distribution.

Base classes

The SDK provides the following base classes to make it easier to implement a plugin that leverages the HttpClient interface. They all provide access to a HttpClient instance using a getHttpClient method:

  • AsyncRuleInterceptorBase

  • AsyncSiteAuthenticatorInterceptorBase

  • AsyncIdentityMappingPluginBase

  • AsyncLoadBalancingPluginBase

Sample plugins

The use of the HttpClient and ThirdPartyServiceModel classes are demonstrated in the following samples provided in the PingAccess distribution:

RiskAuthorizationRule

A rule that obtains a risk score from an external, risk service as well as leveraging the OAuth authorization server to obtain an OAuth access token used to access the risk service.

MetricBasedPlugin

A load balancing strategy that obtains host capacity metadata from an external service.