X

Best Practices from Oracle Development's A‑Team

Go cloud-native with Oracle HCM cloud integrations.

Mani Krishnan

Introduction

Oracle Cloud Infrastructure (OCI) brings new opportunities for customers to rapidly develop, deploy and scale enterprise applications, including extensions to SaaS applications and SaaS integrations. Oracle Cloud Functions and Oracle Kubernetes Engine are cloud-native platforms natively integrated with core OCI services.

Application integration is traditionally left to iPaaS (Integration-platform-as-a-service) platforms such as Oracle Integration Cloud (OIC). OIC remains as a compelling choice for cloud application integrations. However, there can be situations where a cloud-native platform can also be an alternative. For example, an enterprise might have cloud-native talent in-house and too small a number of standalone integrations to implement a dedicated iPaaS platform. There could also be short-lived integration applications needed only for migration into HCM cloud and not needed thereafter, in which case Oracle Cloud Functions can be suitable. In this post, let us look at an integration use case for Oracle HCM application and how to implement it as a function.

What are Oracle Functions?

Oracle Cloud Function is a serverless, functions-as-a-service (FaaS) offering on OCI. It is based on open source Fn project and supports popular runtimes such as python, Java and Node.js. This minimizes the risk of vendor lock-in from building Oracle Functions. The key advantages of function are its serverless nature, its integration with OCI security services and its ability to scale rapidly. Functions have a maximum execution time of 300 seconds, so they are not suitable for bulk-loading jobs that run beyond 5 minutes. For more information, refer to documentation for Oracle Functions and the Fn project.

HCM integration use case

HCM Atom feeds provide the mechanism to get important updates from transactions in Human Capital Management cloud and perform relevant actions. This post explains how to consume Atom feeds and orchestrate tasks for integration using Node.js in Oracle Functions.

For each new hire added to Oracle HCM cloud through web interface, REST API, or HCM Data Loader (HDL) import, Human Capital Management cloud generates an entry in the new hire Atom feeds. Atom feed can be queried by external applications, for example, to add a user account for the new hire in an identity management system.

For this use case, let us assume that workers are migrated from a 3rd party HR application into Oracle HCM cloud and that the employee profile photos are stored in object storage. A solution should locate the profile photo for each employee, apply company logo as background image and then add the photo as profile photo for the employee in HCM cloud. A solution for this use case might easily be modified for other similar use cases. For example, instead of Object storage, the photo could be retrieved from another application using REST endpoint.

OCI Cloud Function-based solution

Here is the high-level logical design of a solution for aforementioned use case.

This solution can be implemented using Oracle Functions, with JavaScript on Node.js runtime. Developers must understand JavaScript promises in order to implement this solution.

Overall, there are five components in the solution. I’ll deal with each briefly and, where applicable, provide sample JavaScript snippets along the way.

Cloud Function 

This is the entry point of the solution, called by OCI upon a request to the function. This component orchestrates the call to all other components. This function also must store and then retrieve any values that need to be retained between runs. Here is an example for main function.

const fdk=require('@fnproject/fdk');

...Other imports...

fdk.handle(async function(input){

  try
  {

	...high-level orchestration logic... 

  return "Completed";
  }
  catch(err)
  {
	console.log("Error:" + err.message);
	return "Error:" + err.message;
  }

})

A function can be triggered in many ways, but invoking them through OCI API gateway is the easiest in my experience. OCI gateway also provides many other features such as configurable API security. Function can also be invoked from fn command line interface. In the example below, a function test-fn from application test-app is invoked with single input parameter.

echo -n '{"object":"config.json"}' | fn invoke test-app test-fn 

OCI Object Storage

Object storage can store photo images to be enhanced and uploaded into HCM cloud as profile photos. Object storage can also store values that need to tracked between runs. For this solution, the date and time of Atom entry processed last must be stored, so that only entries after that entry are processed in the next run. Enforcing resource principal authentication in OCI makes the code simple, as shown below. I’ll elaborate on security in the next section. This snippet shows how to fetch an object from Object Storage.

const os = require("oci-objectstorage");
const common = require("oci-common");

const readObject = async function (input){

  const provider = common.ResourcePrincipalAuthenticationDetailsProvider.builder();

  const bucket = input.bucket;
  const object = input.object;
  const namespace = input.namespace;
  var getObjectResponse = null;

  const client = new os.ObjectStorageClient({
    authenticationDetailsProvider: provider
  });

  try {

    const getObjectRequest = {
      objectName: object,
      bucketName: bucket,
      namespaceName: namespace
    };
    getObjectResponse = await client.getObject(getObjectRequest);

    var objData='';

    for await (const chunk of getObjectResponse.value) {
      objData+= chunk;
    }
    return objData;
  } catch (err) {
    console.log("Error fetching object" + err);
    return  "Error:" + err.message;
  }
};

OCI Vault 

OCI vault provides encrypted storage for credentials. Credentials to access HCM cloud REST API are preferably stored in vault. Check References section below for a link to my colleague’s informative blog on using OCI Vault in JavaScript.

Image processor

This can be a simple image overlay function or something far more sophisticated. For example, facial recognition libraries can be used to ensure that each image has Employee’s face recognizable or that the image is suitable for workplace environment. An implementation will depend on the type and extent of logic and the library or service used.

HCM cloud REST API

HCM REST API is used to first to poll Atom feed and then to update employees’ profile photos, among other things. Configuring security for HCM Cloud deserves a post on it own. I’ve referred to other blogs in References section. Here is a code snippet to invoke HCM REST API. Pay attention to the keywords “async” and “await”, in the calling function.

async function callingfunction(newhire, cfg, input,hcmcredential)
{
...
                try {
                        let http_promise = getWorkerInfoPromise(newhire.PersonNumber,cfg,input.hcmhostname,hcmcredential);
                        let response_body = await http_promise;

                        // holds response from server that is passed when Promise is resolved
                        workerInternalId=JSON.parse(response_body).items[0].links[0].href.split("/")[7];
                }
...
}

//Get more information about worker, so that internal identifier for URL can be determined
function getWorkerInfoPromise(personNumber,cfg,hcmhostname,hcmcredential) {

        return new Promise((resolve, reject) => {
                const https = require('https');

                const options = {
                        hostname: hcmhostname,
                        port: 443,
                        path: '/hcmRestApi/resources/11.13.18.05/workers?q=PersonNumber=' + personNumber,
                        method: 'GET',
                        headers: {
                                'Authorization': hcmcredential
                        }
                }
                https.get(options, (response) => {
                        let chunks_of_data = [];

                        response.on('data', (fragments) => {
                                chunks_of_data.push(fragments);
                        });

                        response.on('end', () => {
                                let response_body = Buffer.concat(chunks_of_data);
                                resolve(response_body.toString());
                        });

                        response.on('error', (error) => {
                                reject(error);
                        });
                });
        });
}

 

Security

Some important aspects of security in this solution are network security, API security, transport layer encryption and encrypted storage of credentials. Let’s address each briefly. Refer to links to blogs and documentation under References section below, for more information.

OCI IAM policies can be configured to enforce Resource principal authentication. It ensures that only authorized OCI services, such as a Function, can access another service or resource in OCI. Once OCI administrator configures it, a function need not pass any credentials explicitly while invoking, for example, Object Storage API. This eliminates the need for developer to obtain, store and pass credentials and mitigates the associated vulnerabilities.

All services hosted on Oracle cloud use TLS 1.2 or higher for transport layer. This solution uses HTTPS for all connections.

This solution stores credentials in OCI vault. OCI vault is made accessible to only to this function using resource principal authentication by the tenancy’s OCI administrator, so that no other applications or users can access the stored credentials. OCI Vault requires a bit of coding and configuration, but it is effective in mitigating vulnerabilities associated with storing credentials in files.

HCM Cloud REST API must also be configured to grant relevant access. There are two levels of security enforced by HCM REST API.

  • A user or application must have a username token or OAuth token accepted by HCM cloud. An oAuth token provider must have its certificate pre-imported into HCM cloud before the tokens are recognized. Username tokens are issued by a HCM cloud security administrator. OAuth is the preferred type of authentication, due to its flexibility in token duration and ability to manage it in HCM Cloud. Both tokens are supplied in “Authentication” HTTP header for REST API.
  • The principal used in the authentication token must be granted a HCM cloud role that permits REST API access. Without this role, the principal might authenticate, but will not be authorized.
  • If applicable, a data security policy must also be configured through a data role. This role will ensure that the principal is permitted access to only relevant data and nothing beyond. For example, data security policy can limit access to information about employees under a specific department.

Network security is an essential aspect of all applications deployed on OCI. For example, access to a service can be limited to a range of IPs. Or, access can be limited only to private subnets of an OCI VCN.

Conclusion

This blog covered the basic concepts behind building a cloud-native integration for HCM cloud, with the focus on Atom feed and HCM REST API. A similar solution can also be built to process HCM HDL-based imports or to deal with extracts. These concepts can also be applied to integrate with other cloud applications. 

References

Oracle Human Capital Management REST API reference.

Oracle Human Capital Management ATOM feeds.

How to configure Resource principal Authentication for functions?

Blog on configuring Oracle Human Capital Management REST API security.

Blog on Oracle Cloud Infrastructure Resource principal authentication for JavaScript.

How to add API gateway as a frontend to functions?

A blog that shows, using JavaScript, how to configure API gateway for functions and to use OCI Vault.