Chapter 4. Design and Development

4.1. Using Developer Portal

To navigate to the Developer Portal, click on the top menu item titled Developer Portal and then select the Visit Developer Portal link on the next row. This will open the Developer Portal page in a new tab.

DeveloperPortal-usage

By default, the Developer Portal is not visible to the public. Users other than admin will be challenged for the Developer Portal Access Code.

DeveloperPortal-usage

This Access Code can be found in the 3scale API Management Platform Admin Portal. Click on the top menu item, titled Settings, and then choose Developer Portal.

DeveloperPortal-usage

Clearing the value for the Developer Portal Access Code makes the site public, and the address can then be bookmarked for quick access without going through the 3scale API Management Platform Admin Portal.

The Developer Portal allows registered users (desktop-user, mobile-user, partner-user and public-user) to access their own corresponding ActiveDocs. Anonymous users will see the following page, asking them to register and get an API key:

DeveloperPortal-usage

A further attempt by an anonymous user to access the documentation will result in the below page, prompting the user to sign in to see ActiveDocs, but also informing the user of the credentials for the public user account.

DeveloperPortal-usage

Registered users who have logged in will see a page displaying their API key (user_key):

DeveloperPortal-usage

Clicking the DOCUMENTATION link takes an authenticated user to a page that displays the ActiveDocs corresponding to their application plan. For desktop-user and mobile-user, as internal users, this means access to the Fuse-gateway-internal ActiveDoc defined in last chapter, which has access to all services exposed by Fuse gateway service:

DeveloperPortal-usage

For partner-user, access is limited to Fuse-gateway-partner ActiveDocs, which only exposes the product service.

DeveloperPortal-usage

For public-user, only access to Fuse-gateway-public ActiveDoc is provided, limiting such users to only product queries.

DeveloperPortal-usage

The ActiveDocs displayed on the DOCUMENTATION page accelerate development by allowing users to explore services, their parameters and responses.

DeveloperPortal-usage

4.2. Accessing the web application

The presentation application is accessible by the desktop-user and calls Fuse gateway service services. The desktop-user is associated with the internal plan, and this application also makes use of all services.

4.2.1. Browser Access

To run the web application, simply point your browser to the address exposed by the route. This address should ultimately resolve to the IP address of an OpenShift host where the router is deployed.

Figure 4.1. Application Homepage before initialization

Uninitialized Application Homepage

Demo data is populated by hitting the demo.jsp page, for example at http://msa.example.com/demo.jsp. After initialization, this page will show the featured products:

Figure 4.2. Application Homepage after initialization

Application Homepage with Sample Data

4.2.2. User Registration

Anonymous users are constrained to browsing inventory, viewing featured products and searching the catalog. To use other features that result in calls to the Sales and Billing services, a valid customer must be logged in.

To register a customer and log in, click on the Register button in the top-right corner of the screen and fill out the registration form:

Figure 4.3. Customer Registration Form

Customer Registration Form

After registration, the purchase button allows customers to add items to their shopping cart, to subsequently visit the shopping cart and check out, and review their order history.

4.3. Rate Limits

Rate Limit is set up for the public plan. The imposed constraint is a maximum of five requests in every one minute.

To see the effect of this Rate Limit, use the curl command example from the Fuse-gateway-public API integration page.

Click on APIs, choose Fuse-gateway-public, click on Integration link, then click edit APICast configuration link.

The curl command is at the bottom.

API-rateLimit

Execute this command multiple times in succession to exceed the limit and a message of Authentication failed will appear instead of the response data.

API-rateLimit

4.4. Analytics feature

Click on the top menu item titled Analytics to view the Monitoring page, containing usage data for all three APIs.

Analytics

Click on an API name to view more details about it. For example, clicking on Fuse-gateway-public should reveal a spike that results from the multiple curl command invocations intended to the rate limit in the previous section.

Analytics

The usage graph for Fuse-gateway-internal will show multiple calls for different services. These service calls were triggered by the web application on different Fuse gateway service operations.

Analytics

Note that registered users can view associated and accessible Analytics data from the Developer Portal. For example, after signing in to the Developer Portal as the desktop-user, click on STATISTICS to view a graph similar to the one displayed below:

Analytics

4.5. Access control using user_key

This reference architecture uses API Key (user_key) for authentication.

Each application has its own user_key. The keys can be found in respective application pages.

Application-user-key

Each calling application uses the assigned user_key, which corresponds to an API’s application plan. The screenshot below shows an example of an HTTP GET call:

API-integration

The user_key and base URL should not be hard-coded in the application source code, as they are prone to later changes. One good example is the use of OpenShift Secret to managing the user_key in OpenShift , which is referenced in the deployment of the presentation service, for example:

The user_key value is stored in an OpenShift Secret, which is defined in the presentation_template.yaml file:

- apiVersion: v1
  kind: Secret
  metadata:
    name: 3scale-secret
    namespace: desktop-project
  stringData:
    user_key: ${USER_KEY_VALUE}

Further down in the presentation_template.yaml file, content from the Secret is referenced and made available as an environment variable.

      spec:
        containers:
        - env:
          - name: USER_KEY
            valueFrom:
                secretKeyRef:
                    name: 3scale-secret
                    key: user_key

The actual value for user_key is passed in as a parameter during deployment. The use of a parameter instead of an environment variable has the advantage that parameters won’t be kept in memory, so credentials won’t be exposed. Since the base URL is not sensitive information, it can be passed in as an environment variable during pod creation.

$ oc new-app -p USER_KEY_VALUE=9331104b50c0385cc64ebd72a38d4a56 -e SERVICE_ADDRESS=fuse-gateway-internal-3scale-apicast-staging.middleware.ocp.cloud.lab.eng.bos.redhat.com --file=presentation_template.yaml

Then RestClient.java code in the service can then retrieve both data as environment variable values and use them in the web address:

public class RestClient {
    public static String  userKey = System.getenv("USER_KEY");
    public static String serviceAddress = System.getenv("SERVICE_ADDRESS");

For troubleshooting purpose, this reference architecture’s presentation layer uses the JavaScript console to log the two variables' runtime value. This allows users to verify the actual values. To see these two values in Google Chrome, go to setting, More tools, Developer Tools, and click Console.

user_key1

4.6. Prevent bypassing API gateway through secret token

The network topology is often effective in blocking unauthorized access to internal services. When Red Hat 3scale API Management Platform is used to introduce a gateway, direct access to the underlying API is often blocked through network tools. In cases where such configuration is impossible or insufficient, the secret token feature of 3scale API Management Platform can be used to achieve similar results.

When enabled, 3scale API Management Platform hard codes a token in the HTTP header of all requests passing through the gateway. Applications exposing the managed API would then have to check for the existence of this token and reject any requests that do not contain it. As long as the value of this token is kept private, the only way to access such API would be through the gateway.

There are two steps to turn this feature on.

First, in 3scale API Management Platform Admin Portal, click on the top menu item titled API, then choose Integration for the API that needs to be secured. Click the AUTHENTICATION SETTINGS drop-down list and give Secret Token a value.

secret_token

Second, in the application code for the managed API, check all request for a token name of X-3scale-proxy-secret-token in the HTTP header. Reject any requests that do not provide a value for this token, or have an incorrect value.

For example, the following code snippet from the Fuse gateway service shows an example of how to enforce the Secret Token.

    @Value('${gateway.token.header:X-3scale-proxy-secret-token}')
    String tokenHeader

    @Value('${gateway.token.value:#{null}}')
    String tokenValue

    Logger logger = Logger.getLogger(AppRoute.class.name)

    @Override
    void configure() throws Exception {

        if (tokenValue != null && tokenHeader != null) {

            logger.info("AUTH TOKEN REQUIREMENT DETECTED: [${tokenHeader}] adding security route interceptor")
            interceptFrom().id("auth token interceptor").process(new Processor() {
                @Override
                void process(Exchange exchange) throws Exception {

                    if (exchange.in.getHeader(tokenHeader) == null
                            || exchange.in.getHeader(tokenHeader) != tokenValue) {

                        logger.info("Authorization token required, but header missing or invalid")
                        exchange.out.setHeader(Exchange.HTTP_RESPONSE_CODE, 403)
                        exchange.out.setBody("Unauthorized [missing or invalid token]")
                        exchange.setProperty(Exchange.ROUTE_STOP, Boolean.TRUE)
                    }
                }
            })
        }

The secret token in inject into the Fuse gateway service pod as an environment variable to avoid hard-coding it.

secret_token

In this example, the token value is set to Shared_secret_sent_from_proxy_to_API_backend_12345678987654321. Changing this value in the 3scale API Management Platform Admin Portal without updating it in the Fuse gateway service code would result in the API integration test failing, since the value passed from 3scale API Management Platform to Fuse gateway service will not match.

secret_token

Once the security token is set up, both in 3scale API Management Platform and Fuse gateway service, requests to the Fuse gateway service API need to go through 3scale API Management Platform first; otherwise, the request will fail, as it will not have the secret security token in the header.

To demonstrate this, try the two following curl commands to the same Fuse gateway service API, where the first one bypasses the 3scale API Management Platform and uses the Fuse gateway service gateway IP address directly, while the second request goes through 3scale API Management Platform as expected.

curl http://172.30.124.155:9091/products?featured=1

curl "https://fuse-gateway-internal-3scale-apicast-staging.middleware.ocp.cloud.lab.eng.bos.redhat.com:443/products?featured=1&user_key=876286f7c3cf24899c6f390464c41429"

The first requests fails with a message of missing or invalid token, while the second command returns the expected response.

secret_token

4.7. Updating Swagger files

To create a new service spec, the swagger file for the new service is required. The reference architecture’s Fuse gateway service provided a swagger file at http://api.example.com/api-doc/swagger.json after installation. Several updates are required to this file before it can be used in this project:

  • Update the host to the correct value. Red Hat 3scale API Management Platform doesn’t allow IP address, so please use either the Staging Public Base URL or the Production Public Base URL instead:
"host" : "fuse-gateway-service-3scale-apicast-staging.apimgmt.example.com:443",
  • Update the scheme to HTTPS, as it is the default protocol used by 3scale API Management Platform:
"schemes" : [ "https" ],
  • For each service, add one more parameter called user_key for authentication. This parameter is not included in the Swagger file originally provided by the Fuse gateway service.

Note that only one parameter called customerId is included in the file:

    "/customers/{customerId}" : {
      "get" : {
        "tags" : [ "customers/{customerId}" ],
        "summary" : "get customer",
        "produces" : [ "application/json" ],
        "parameters" : [ {
          "name" : "customerId",
          "in" : "path",
          "description" : "id of customer to fetch",
          "required" : true,
          "type" : "string"
        } ],
        "responses" : {
          "200" : {
            "description" : "customer fetched",
            "schema" : {
              "$ref" : "#/definitions/Customer"
            }
          }
        },
        "x-camelContextId" : "camel-1",
        "x-routeId" : "route7"
      },

Add the new parameter:

    "/customers/{customerId}" : {
      "get" : {
        "tags" : [ "customers/{customerId}" ],
        "summary" : "get customer",
        "produces" : [ "application/json" ],
        "parameters" : [ {
          "name" : "customerId",
          "in" : "path",
          "description" : "id of customer to fetch",
          "required" : true,
          "type" : "string"
        },
        {
            "name": "user_key",
            "in": "query",
            "description": "Your API access key",
            "required": true,
            "x-data-threescale-name": "user_keys",
            "type": "string"
        }
         ],
        "responses" : {
          "200" : {
            "description" : "customer fetched",
            "schema" : {
              "$ref" : "#/definitions/Customer"
            }
          }
        },
        "x-camelContextId" : "camel-1",
        "x-routeId" : "route7"
      },

4.8. Developer Portal DOCUMENTATION page

Liquid is a simple programming language used for displaying and processing most of the data from the 3scale system available for API providers.

Use Liquid control flow tags if and elsif to limit access for each registered user to their own ActiveDocs:

      	{% if current_user.username == 'desktop-user' or  current_user.username == 'mobile-user' %}
          {% active_docs version: "2.0" services: "Fuse-gateway-internal" %}
            ...............

      	{% elsif current_user.username == 'partner-user' %}
          {% active_docs version: "2.0" services: "Fuse-gateway-partner" %}
            ...............

      	{% elsif current_user.username == 'public-user' %}
          {% active_docs version: "2.0" services: "Fuse-gateway-public" %}
            ...............

		{% endif %}

Refer to the product documentation on how to publish ActiveDocs in the Developer Portal.

          <script type="text/javascript">
            $(function () {
                window.swaggerUi.options['docExpansion'] = 'none';
                window.swaggerUi.options['url'] = "https://3scale.apimgmt.example.com/swagger/spec/Fuse-gateway-internal.json";
              window.swaggerUi.load();
            });
          </script>

For more information on using Liquid and Developer Portal, please refer to Liquids: Developer Portal and the Liquid Reference pages.