Example with SalesForce REST API

Introduction

The following ResourceResolver bean definition is an example configuration for SalesForce REST API backend. This will give hints on how to configure conneciton information, RestTemplate object configuration, authentication such as OAuth2, ResourceLinkResolver object configuration, cache control configuration, etc.

The following ResourceResolver Spring Framework Beans configuration can be set at /hippo:configuration/hippo:modules/crispregistry/hippo:moduleconfig/crisp:resourceresolvercontainer/demoSalesForce/@crisp:beandefinition property in the repository for "demoSalesForce" resource space, for instance.

ResourceResolver Configuration

Bloomreach Experience Manager 16:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:s="http://www.springframework.org/schema/security"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
                        http://www.springframework.org/schema/security
            https://www.springframework.org/schema/security/spring-security.xsd
                        http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                        http://www.springframework.org/schema/util
                        http://www.springframework.org/schema/util/spring-util.xsd">

  <bean parent="abstractCrispSimpleJacksonRestTemplateResourceResolver"
        class="org.onehippo.cms7.crisp.core.resource.jackson.SimpleJacksonRestTemplateResourceResolver">
    <property name="cacheEnabled" value="${cache.enabled}" />
    <property name="baseUri" value="${salesforce.baseUrl}/services/data/v20.0" />
    <property name="resourceDataCache">
      <bean class="org.onehippo.cms7.crisp.core.resource.SpringResourceDataCache">
        <constructor-arg>
          <bean class="org.springframework.cache.caffeine.CaffeineCache" factory-bean="caffeineCacheInstanceFactory" factory-method="createSpringCacheInstance">
            <constructor-arg value="demomarketoCache" />
            <constructor-arg value="initialCapacity=10,maximumSize=1000,expireAfterWrite=100s,expireAfterAccess=100s" />
          </bean>
        </constructor-arg>
      </bean>
    </property>
    <property name="clientHttpRequestInterceptor">
      <list value-type="org.springframework.http.client.ClientHttpRequestInterceptor">
        <bean class="org.onehippo.cms7.crisp.core.interceptor.SimpleOAuth2AuthorizedClientInterceptor" autowire="constructor">
          <property name="authorizedClientService" ref="authorizedClientService" />
          <property name="clientRegistrationId" value="salesforce-login" />
          <property name="contextAttributesMap" ref="credentials" />
        </bean>
      </list>
    </property>
  </bean>
  <util:map id="credentials" map-class="java.util.HashMap">
      <entry key="org.springframework.security.oauth2.client.OAuth2AuthorizationContext.USERNAME">
          <value>${salesforce.username}</value>
      </entry>
      <entry key="org.springframework.security.oauth2.client.OAuth2AuthorizationContext.PASSWORD">
          <value>${salesforce.password}</value>
      </entry>
  </util:map>

  <s:client-registrations>
      <s:client-registration registration-id="salesforce-login"
                             client-id="${salesforce.clientId}"
                             client-secret="${salesforce.clientSecret}"
                             client-authentication-method="post"
                             authorization-grant-type="password"
                             provider-id="salesforce"/>
      <s:provider provider-id="salesforce"
                  authorization-uri="${salesforce.baseUrl}/services/oauth2/token"
                  token-uri="${salesforce.baseUrl}/services/oauth2/token"/>
  </s:client-registrations>

  <bean id="authorizedClientService" class="org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService" autowire="constructor"/>
  <bean id="authorizedClientRepository" class="org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository">
    <constructor-arg ref="authorizedClientService"/>
  </bean>

</beans>

Bloomreach Experience Manager 14 & 15:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:s="http://www.springframework.org/schema/security"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
                        http://www.springframework.org/schema/security
            https://www.springframework.org/schema/security/spring-security.xsd
                        http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                        http://www.springframework.org/schema/util
                        http://www.springframework.org/schema/util/spring-util.xsd">

  <bean parent="abstractCrispSimpleJacksonRestTemplateResourceResolver"
        class="org.onehippo.cms7.crisp.core.resource.jackson.SimpleJacksonRestTemplateResourceResolver">
    <property name="cacheEnabled" value="${cache.enabled}" />
    <property name="baseUri" value="${salesforce.baseUrl}/services/data/v20.0" />
    <property name="resourceDataCache">
      <bean class="org.onehippo.cms7.crisp.core.resource.SpringResourceDataCache">
        <constructor-arg>
          <bean class="org.springframework.cache.ehcache.EhCacheCache">
            <constructor-arg>
              <bean parent="abstractCrispResourceEhCache">
                <property name="cacheName" value="demoSalesForceCache" />
                <property name="maxEntriesLocalHeap" value="1000" />
                <property name="maxEntriesLocalDisk" value="0" />
                <property name="timeToLiveSeconds" value="60" />
                <property name="timeToIdleSeconds" value="60" />
              </bean>
            </constructor-arg>
          </bean>
        </constructor-arg>
      </bean>
    </property>
    <property name="clientHttpRequestInterceptor">
      <list value-type="org.springframework.http.client.ClientHttpRequestInterceptor">
        <bean class="org.onehippo.cms7.crisp.core.interceptor.SimpleOAuth2AuthorizedClientInterceptor" autowire="constructor">
          <property name="authorizedClientService" ref="authorizedClientService" />
          <property name="clientRegistrationId" value="salesforce-login" />
          <property name="contextAttributesMap" ref="credentials" />
        </bean>
      </list>
    </property>
  </bean>
  <util:map id="credentials" map-class="java.util.HashMap">
      <entry key="org.springframework.security.oauth2.client.OAuth2AuthorizationContext.USERNAME">
          <value>${salesforce.username}</value>
      </entry>
      <entry key="org.springframework.security.oauth2.client.OAuth2AuthorizationContext.PASSWORD">
          <value>${salesforce.password}</value>
      </entry>
  </util:map>

  <s:client-registrations>
      <s:client-registration registration-id="salesforce-login"
                             client-id="${salesforce.clientId}"
                             client-secret="${salesforce.clientSecret}"
                             client-authentication-method="post"
                             authorization-grant-type="password"
                             provider-id="salesforce"/>
      <s:provider provider-id="salesforce"
                  authorization-uri="${salesforce.baseUrl}/services/oauth2/token"
                  token-uri="${salesforce.baseUrl}/services/oauth2/token"/>
  </s:client-registrations>

  <bean id="authorizedClientService" class="org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService" autowire="constructor"/>
  <bean id="authorizedClientRepository" class="org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository">
    <constructor-arg ref="authorizedClientService"/>
  </bean>

</beans>

The following properties are used in the bean configuration through pairs of crisp:propnames and crisp:propvalues properties at /hippo:configuration/hippo:modules/crispregistry/hippo:moduleconfig/crisp:resourceresolvercontainer/demoSalesForce node for "demoSalesForce" resource space, for instance.

Property Name Example Value
cache.enabled true
salesforce.clientId someClientId
salesforce.clientSecret someClientSecret
salesforce.username [email protected]
salesforce.password somePassword
salesforce.securityToken someSecurityToken
salesforce.baseUrl https://na1.salesforce.com
  • cacheEnabled property is to enable or disable ResourceResolver level caching.
  • baseUri property is to set the base URI of the backend SalesForce REST API. So, invocations on ResourceServiceBroker for this resource space will take a relative resource path to combine it with the base URI to invoke the backend SalesForce REST API in the end.
  • resourceDataCache property specifies a ResourceResolver specific ResourceDataCache object. If this property is set and the specific resource is cacheable, the ResourceServiceBroker may cache resource specific data in the specified ResourceDataCache. If not set but the specific resource is still cacheable, ResourceServiceBroker may cache resource specific data in a globally-shared ResourceDataCache by default.
  • Finally, clientHttpRequestInterceptor property specifies a SimpleOAuth2AuthorizedClientInterceptor object. In this example, because the SalesForce REST API backend requires OAuth2 authentication, a OAuth2 client needs to be registered in the OAuth2AuthorizedClientRepository with all the necessary OAuth2 authentication information. Please note that the spring-security-oauth2 project is deprecated and the related libraries will be removed in the next versions. Below you can find a possible implementation of the SimpleOAuth2AuthorizedClientInterceptor.
package org.onehippo.cms7.crisp.core.interceptor;

import ...

public class SimpleOAuth2AuthorizedClientInterceptor implements ClientHttpRequestInterceptor {

    private ClientRegistrationRepository clientRegistrationRepository;
    private OAuth2AuthorizedClientService authorizedClientService;
    private AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager;
    private String clientRegistrationId;
    private Authentication principal;
    private Map<String, Object> contextAttributesMap;

    public SimpleOAuth2AuthorizedClientInterceptor(ClientRegistrationRepository clientRegistrationRepository) {
        Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
        this.clientRegistrationRepository = clientRegistrationRepository;
    }

    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
            throws IOException {

        if (this.authorizedClientManager == null) {
            final OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
                    .clientCredentials()
                    .refreshToken()
                    .password()
                    .authorizationCode()
                    .build();

            this.authorizedClientManager =
                    new AuthorizedClientServiceOAuth2AuthorizedClientManager(this.clientRegistrationRepository, this.authorizedClientService);
            this.authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
            this.authorizedClientManager.setContextAttributesMapper(oAuth2AuthorizeRequest -> contextAttributesMap);
        }

        final OAuth2AuthorizeRequest oAuth2AuthorizeRequest = OAuth2AuthorizeRequest
                .withClientRegistrationId(this.clientRegistrationId)
                .principal(getPrincipal())
                .build();
        final OAuth2AuthorizedClient authorizedClient = authorizedClientManager.authorize(oAuth2AuthorizeRequest);

        final HttpHeaders headers = request.getHeaders();
        headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue());

        return execution.execute(request, body);
    }

...
    
}
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?