Views:

Last Updated: 7/5/2021 12:10:13 AM

Sample Code

The samples demonstrate how to interact with SMPI by sending an https request along with authentication headers. Before you use SMPI, you should have applied a pair of Secret Key and Access Token, credentials that will help SMPI recognize you as a valid integrating partner of Trend Micro. For the guide of applying API credential, please refer to Invoking SMPI.

After implementation, you can go to Check if your signature is correct.

Python

smpi_connection.py

import base64
import calendar
import hashlib
import hmac
import httplib
import time
import uuid

class SMPIConnection(object):
    def __init__(self, access_token, secret_key, hostname, port, timeout=30):
        self.access_token = access_token
        self.secret_key = secret_key
        self.hostname = hostname
        self.port = port
        self.timeout = timeout

        self.connect()

    def __del__(self):
        self.close()

    def connect(self):
        if int(self.port) == 443:
            self.conn = httplib.HTTPSConnection(self.hostname, self.port,
                                                timeout=self.timeout)
        else:
            self.conn = httplib.HTTPConnection(self.hostname, self.port,
                                               timeout=self.timeout)

    def send_request(self, http_method, request_uri, body=None):
        '''
        Send request to access SMPI
        '''
        headers = get_auth_headers(self.access_token, self.secret_key,
                                   http_method, request_uri, body)
        self.conn.request(http_method, request_uri, body, headers)
        resp = self.conn.getresponse()
        return (resp.status, resp.read())

    def close(self):
        self.conn.close()

def get_auth_headers(access_token, secret_key, method, request_uri, body):
    '''
    Generate authentication herders
    '''
    posix_time = calendar.timegm(time.gmtime())

    headers = {}
    headers["content-type"] = "application/json"
    headers["x-access-token"] = access_token
    headers["x-signature"] = \
        gen_x_signature(secret_key, str(posix_time),
                        method, request_uri, body)
    headers["x-posix-time"] = posix_time
    headers["x-traceid"] = str(uuid.uuid4())

    return headers

def gen_x_signature(secret_key, x_posix_time, request_method, request_uri,
                    body):
    '''
    Generate x-signature
    '''
    payload = x_posix_time + request_method.upper() + request_uri
    if body:
        payload += get_content_md5(body)
    hm = hmac.new(secret_key.encode("utf8"),
                  payload.encode("utf8"), hashlib.sha256)
    digest = hm.digest()
    digest = base64.b64encode(digest)
    return digest

def get_content_md5(content):
    '''
    Get hashed content
    '''
    m = hashlib.md5()
    m.update(content)
    digest = m.digest()
    digest = base64.b64encode(digest)

    return digest

The following code shows you how to access SMPI using SMPIConnection. For example, we call GET /SMPI/service/wfbss/api/customers to list all the WFBSS customers.

import json
from smpi_connection import SMPIConnection

ACCESS_TOKEN = "<em>c137ff67-c53d-4c91-9e84-81025a721ca2</em>"  # Your access token
SECRET_KEY = "<em>L/HXx2y1RpIE94Zx2EikeCtkO7G+Y6Qibk7uNd5llRU=</em>"  # Your secret key

CSPI_SERVER_HOSTNAME = "smpi-nabu.sco.trendmicro.com" # SMPI URL
CSPI_SERVER_PORT = "443"

if __name__ == '__main__':
    smpi_conn = SMPIConnection(ACCESS_TOKEN, SECRET_KEY,
                               SMPI_SERVER_HOSTNAME, SMPI_SERVER_PORT)

    # Example to call GET /SMPI/service/wfbss/api/customers
    method = "GET"
    request_uri = "/SMPI/service/wfbss/api/customers"
    res_status, res_data = smpi_conn.send_request(method, request_uri)

    print "Response status: \n%s",  res_status
    print "Response data: \n%s", res_data

C#

cspi_auth-headers.cs

using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        public static string ACCESS_TOKEN = "c137ff67-c53d-4c91-9e84-81025a721ca2";
        public static string SECRET_KEY = "L/HXx2y1RpIE94Zx2EikeCtkO7G+Y6Qibk7uNd5llRU=";

        static void Main(string[] args)
        {
            string scheme = "https";
            string host = "SMPI_URL";
            string uri = "/SMPI/service/wfbss/api/customers";
            long posixTime = GetPosixTime();
            string httpMethod = "GET";
            string jsonContent = "";

            //Get Test(Care the different of payload with other HTTPMethod)
            SendRequest(scheme, host, uri, posixTime, httpMethod, jsonContent);
            Console.ReadLine();
        }

        public static void SendRequest(string scheme, string host, string uri, long posixTime, string httpMethod, string jsonContent)
        {
            byte[] contentBytes = null;
            bool isGet = string.Equals(httpMethod, "GET", StringComparison.OrdinalIgnoreCase);

            if (isGet == false)
            {
                contentBytes = Encoding.UTF8.GetBytes(jsonContent);
            }

            string signature = GenerateSignature(SECRET_KEY, posixTime, httpMethod, uri, contentBytes);

            // Create the web request and headers.
            var request = (HttpWebRequest)WebRequest.Create(scheme + "://" + host + uri);
            request.ContentType = "application/json; charset=utf-8";
            request.Method = httpMethod;
            request.Headers.Add("x-access-token", ACCESS_TOKEN);
            request.Headers.Add("x-posix-time", posixTime.ToString());
            request.Headers.Add("x-signature", signature);
            request.Headers.Add("x-traceid", Guid.NewGuid().ToString());

            // Set the content length in the request headers  
            request.ContentLength = isGet ? 0 : contentBytes.Length;

            // Write data  
            if (isGet == false)
            {
                using (Stream postStream = request.GetRequestStream())
                {
                    postStream.Write(contentBytes, 0, contentBytes.Length);
                } 
            }

            // Get response
            try
            {
                using (var response = (HttpWebResponse)request.GetResponse())
                {
                    // Get the response stream  
                    var reader = new StreamReader(response.GetResponseStream());

                    // Console application output  
                    Console.WriteLine("HTTP " + (int)response.StatusCode + " " + response.StatusCode);
                    Console.WriteLine("\nResponse Content:");
                    var responseContent = reader.ReadToEnd();
                    Console.WriteLine(responseContent);

                }
            }
            catch (WebException we)
            {
                Console.WriteLine(we);
                // Get the error response stream  
                HttpWebResponse webResponse = (HttpWebResponse)we.Response;
                var reader = new StreamReader(webResponse.GetResponseStream());

                // Console application output  
                Console.WriteLine("HTTP " + (int)webResponse.StatusCode + " " + webResponse.StatusCode);
                Console.WriteLine("\nResponse Content:");
                var responseContent = reader.ReadToEnd();
                Console.WriteLine(responseContent);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }
        public static long GetPosixTime()
        {
            return ((long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds);
        }

        ///
        /// Generate a x-signature header value that's required to invoke LMPI api interface
        ///
        ///The secrect key used to hash
        ///Number of secods after 1970-01-01 til now
        ///HTTP method used to invoke LMPI
        ///
        ///     the requiesting Uri without server host. The request uri should be precent-encoded
        ///
        ///http request content in binary. Pass in null if no content is to be sent to server
        ///a hexstring of HMAC-SHA256 hashed value will be assigned to this parameter
        ///Base64 string encoded x-signature
        public static string GenerateSignature(string secret, long unixTimestamp, string method, string requestUri, byte[] content)
        {
            var posix = unixTimestamp.ToString();
            var payload = posix + method.ToUpper() + requestUri + ((content == null) ? "" : CalculateMD5Hash(content));

            HMAC hash = new HMACSHA256();
            hash.Initialize();
            hash.Key = Encoding.UTF8.GetBytes(secret);

            var byteArr = hash.ComputeHash(Encoding.UTF8.GetBytes(payload));

            return Convert.ToBase64String(byteArr);
        }

        ///
        /// Calculates MD5 Hash of a binary and return it as a base64 string.
        ///
        ///binary to be calculated
        /// MD5 hashed string result in Base64
        public static string CalculateMD5Hash(byte[] input)
        {
            // step 1, calculate MD5 hash from input
            MD5 md5 = MD5.Create();
            byte[] hash = md5.ComputeHash(input);

            return Convert.ToBase64String(hash);
        }
    }
}

"Java

APITest.java

import java.io.*;
import java.net.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.UUID;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

/**
 * This example uses Apache HttpClient 4.x  library to invoke REST API call. Please refer to:
 * http://hc.apache.org/httpcomponents-client-ga/index.html
 *
 */
public class APITest
{
    // use the access_token and secret_key that's been assigned to you
    public static String ACCESS_TOKEN = "c137ff67-c53d-4c91-9e84-81025a721ca2";
    public static String SECRET_KEY = "L/HXx2y1RpIE94Zx2EikeCtkO7G+Y6Qibk7uNd5llRU=";

    /**
     * @param args
     */
    public static void main(String[] args) {
        long posix;
        URIBuilder builder = new URIBuilder();
        String httpMethod;
        String jsonContent;

        try{
            //Get
            posix = getPosixTime();
            builder.setScheme("https")
                    .setHost("SMPI_URL")
                    .setPath("/SMPI/service/wfbss/api/customers");
            httpMethod = "GET";
            jsonContent = null;
            requestAPI(posix, builder, httpMethod, jsonContent);
        }catch(URISyntaxException e1){
            System.out.println(e1.toString());
        }catch(UnsupportedEncodingException e2){
            System.out.println(e2.toString());
        }
    }

    private static long getPosixTime() {
        return new Date().getTime() / 1000L;
    }

    /**
     * Generate a x-signature header value that is required to invoke LMPI
     * @param secret The secret key assigned by Trend Micro
     * @param unixTimestamp The x-posix-time attribute specified in header, it is suppose to the request time in unix timestamp format.
     * @param method The HTTP method that is used to invoke LMPI
     * @param uri The absolute uri being requested. The url should url-encoded that is similar to something like:
     *  /customers?name=some%20customer%20name
     * @param content The HTTP content that is to be hashed, pass null if there's no content to be hashed.
     * @return a SHA-256 hashed digest in Base64 string.
     */
    public static String GenerateSignature(String secret, long unixTimestamp,
                                           String method, String uri, byte[] content)
    {
        MessageDigest md = null;

        String posix = String.valueOf(unixTimestamp);
        String payload = posix + method.toUpperCase() + uri;
        String contentBase64 = "";

        // Create a MD5 hash of content if not null.
        if(content != null){
            try {
                md = MessageDigest.getInstance("MD5");
                md.update(content);
                contentBase64 = Base64.encodeBase64String(md.digest());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            payload += contentBase64;
        }

        try{
            Mac hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
            hmac.init(secret_key);

            byte[] hashed = hmac.doFinal(payload.getBytes("UTF-8"));
            return new Base64().encodeAsString(hashed);

        }catch(Exception ex){
            System.out.println("unable to create message hash." + ex.toString());
        }
        return null;
    }

    public static void requestAPI(long posix, URIBuilder builder, String httpMethod, String jsonContent)
            throws URISyntaxException, UnsupportedEncodingException
    {
        HttpClient httpClient = HttpClientBuilder.create().build();

        // build requesting URI
        URI uri = builder.build();

        // prepare HTTP Post object
        HttpRequestBase op;
        if (httpMethod == null) throw new NullPointerException("HttpMethod cna't be null");
        httpMethod = httpMethod.toUpperCase();

        if (httpMethod.equals("GET")) {
            op = new HttpGet(uri);
        } else if (httpMethod.equals("DELETE")) {
            op = new HttpDelete(uri);
        } else {
            HttpEntityEnclosingRequestBase requestBase = null;
            if (httpMethod.equals("PUT")) {
                requestBase = new HttpPut(uri);
            } else if (httpMethod.equals("POST")) {
                requestBase = new HttpPost(uri);
            } else {
                throw new UnsupportedOperationException("HttpMethod must be GET, POST, POST or DELETE");
            }
            // prepare content
            StringEntity entity = new StringEntity(jsonContent);
            requestBase.setEntity(entity);
            op = requestBase;
        }

        op.addHeader("x-access-token", ACCESS_TOKEN);
        op.addHeader("x-signature",
                GenerateSignature(SECRET_KEY, posix, httpMethod, uri.getPath(), jsonContent == null ? null : jsonContent.getBytes("UTF-8")));
        op.addHeader("x-posix-time", String.valueOf(posix));
        op.addHeader("x-traceid", UUID.randomUUID().toString());
        op.addHeader("content-type", "application/json;charset=UTF-8");

        // Receive response
        try{
            HttpResponse response = httpClient.execute(op);
            String responseContent = EntityUtils.toString(response.getEntity());
            System.out.println("Response status: " + response.getStatusLine());
            System.out.println("Response content: " + responseContent);
        } catch (ClientProtocolException e) {
            System.out.println(e.toString());
        } catch (IOException e) {
            System.out.println(e.toString());
        }

    }
}

Check if your x-signature is correct

1. 
    Access token: c137ff67-c53d-4c91-9e84-81025a721ca2
    Secert key: L/HXx2y1RpIE94Zx2EikeCtkO7G+Y6Qibk7uNd5llRU=
    Request Method: GET
    Request Path: /SMPI/service/wfbss/api/customers
    Request Body: No request body
    POSIX time: 1446422400

    The correct x-signature shoule be: 
    Therefore, the HTTP header will look like: 6mU4SfJzos4ZaEGticXUYnNCwNr85dCyfbpMyLcQGiI=
        x-access-token: c137ff67-c53d-4c91-9e84-81025a721ca2
        x-posix-time: 1446422400
        x-signature: 6mU4SfJzos4ZaEGticXUYnNCwNr85dCyfbpMyLcQGiI=
        x-traceid: 975f9ce9-f509-4842-8c2e-9f0b1f27e1b3
        content-type: application/json

2.
    Request Method: PUT
    Request Path: /SMPI/v2/service/wfbss/api/global_settings?cids=640FE47F-5118-4D79-8221-A35D0DE2EE2C
    Request Body:
        {
            "replicate_from": {
                "cid": "A9CC5A34-3CAD-480D-A9ED-87656316D3B9"
            }
        }
    POSIX time: 1446422400

    The correct x-signature shoule be: Tmy4RlR65zN9UPvTdZncN23R2EZqMgmE3Ry3FFrDDsg=
    Therefore, the HTTP header will look like:
        x-access-token: c137ff67-c53d-4c91-9e84-81025a721ca2
        x-posix-time: 1446422400
        x-signature: Tmy4RlR65zN9UPvTdZncN23R2EZqMgmE3Ry3FFrDDsg=
        x-traceid: 975f9ce9-f509-4842-8c2e-9f0b1f27e1b3
        content-type: application/json