citrix cpbm logo

Working with the Citrix CloudPortal Business Manager 2.1 BSS API

Citrix CloudPortal Business Manager (CPBM) enables Enterprises and Service Providers to move towards an IT-as-a-Service model by managing and delivering a broad array of internal, external and 3rd party Cloud and IT services through a single, comprehensive, self-service portal. It also unifies and simplifies the commerce, user management, service provisioning and operational aspects of running a Cloud in a customisable user interface.

The CPBM 2.1 release introduces the BSS Application Programming Interface (API) for enabling the integration of CPBM with existing business, operations and IT systems such as CRM, financials, etc. In this article Tariq Iqbal, Senior Consultant at ShapeBlue , shows how to unleash the power of this API.

The BSS API focuses on application and service integration to a wide array of internal and external business and operations support systems; helping to unify and automate the delivery of ITaaS. Some examples include:

  • Exporting invoices created in CPBM to a customer’s invoicing system for payment
  • Update CPBM user accounts with details of payments collected by an external system
  • Change the state of CPBM user accounts from Active to Suspended from another system
  • Automate the creation/update of user accounts in external monitoring/support systems

 

Having successfully integrated CPBM with a number of solutions (SAP, Billing, Monitoring, ServiceDesk) for customers; the BSS API has been a sought-after feature here at ShapeBlue.

However, as many have found the supporting BSS API documentation from Citrix is poor and hopefully this article will save you the many painful hours I had to endure to see those API responses from CPBM.

 

BSS API

The CPBM BSS API provides a ReSTful (Representational State Transfer) web service interface and supports four possible actions (Get, Put, Post, and Delete) on exposed resources – you can find the full list of resources here.

The BSS API works through the ports which are configured for CPBM, typically port 8080. If the CPBM UI can be opened through that port then the CPBM APIs can also be accessed by those ports.

The BSS API responses are returned in either JSON (default) or XML formats.

 

BSS API Request Format

Every BSS API request has the following format: 

Base_URL + Base_API_Path + REST_API_Path ? Parameter_String & Signature

Where:

Base_URL: CPBM Server URL. eg: http://localhost:8080

Base_API_Path: path to the base API Servlet that processes the incoming requests. eg: /portal/api

REST_API_Path: path to CPBM rest api controller/resource. eg: /accounts

Parameter_String: includes a minimum APIKey + Timestamp. Additional parameters are dependent on the resource requested.
eg:  _=1386548174877&apiKey=3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg

Signature: is an encoded security signature that changes with every requests and is generated using the Secret Key and the parameters in the Parameter_String.
eg: signature=GuztixGDmF6W9R6bvKjfV7as05o%3D

By default the signature is valid for 5 minutes. This can be configured on a as need basis through updating ‘signature.timeout‘ under Administration > Configuration > Portal > Server:

citrix cpbm screenshot

  

Complete URL:

http://localhost:8080/portal/api/accounts?
_=1386548174877
&apiKey=3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg
&signature=GuztixGDmF6W9R6bvKjfV7as05o%3D

 

Generating the BSS API Request

Assuming you have access to the CPBM server, here are the steps for generating a BSS API request.

By way of an example, we will create an API request for listing the user accounts in CPBM and will refer to the following during the signature generation:

REST_API_Path: /accounts

Parameter_String: _=1386548174877&apiKey=3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg

1. Obtain the field.encryption.key property value

Locate the field.encryption.key property value in /usr/share/vts3/repository/prop/cloud.properties

2. Obtain the API Key and Secret Key for a specific user

The operations you can perform through the BSS API depend on the user account you wish to use to make the API call and this also affects the parameters that need to be sent in the BSS API request – details of what operations are permitted for each type of user and what parameters are required can be found in the CPBM 2.1 documentation.

The API Key and Secret Key are obtained from the cloud_portal.users database table and not from the keys found in the CPBM UI under ‘My Profile > API Credentials’ (these keys are for use against Citrix CloudPlatform or Apache CloudStack).

The api_key field value can be used in the API request as is, but the secret_key field in cloud_portal.users is encrypted and requires AES decryption using the field.encryption.key (from step 1) to obtain the actual value.

So to get the API Key and Secret Key for the root user, run the following SQL query against the CPBM database, substituting your own value for field.encryption.key:

SELECT id, username, api_key, convert(aes_decrypt(unhex(secret_key), ‘field.encryption.key‘) using UTF8) secret_key FROM users WHERE username=’root’\G

Output:

id: 1

username: root

api_key: 3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg

secret_key: p5VBDWN7QgrZEfMdSaL7_KN6TQU_1Dfwu5dHqzZ1fBGD_SOjuimuD8VSUND7OKQHvj0oG86WfqrJ6Q-v5P6r1Q

3. Generate the Signature

1) For each field-value pair (as separated by a ‘&’) in the Parameter_String, encode each value so that it can be safely sent via HTTP GET.  Note: To overcome a defect in CPBM make sure all spaces(+) are encoded as “%20″:

Parameter_String=_=URLENCODE(1386548174877)& apiKey=URLENCODE(3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg)

2) Lower case the entire Parameter_String and sort it alphabetically via the field for each field-value pair:

Parameter_String=_=1386548174877&apiKey=3jvtagoc6k5rdhw8fmatbloccnnrtlby-bhimlt9y94ojyvg3fns1csqdxtxia7ffjarhs-qjqt18tu9eyntsg

3) Prefix the Parameter_String with the REST_API_Path:

Parameter_String=/accounts_=1386548174877&apiKey=3jvtagoc6k5rdhw8fmatbloccnnrtlby-bhimlt9y94ojyvg3fns1csqdxtxia7ffjarhs-qjqt18tu9eyntsg

4) Take the prefixed Parameter_String and run it through the HMAC SHA-1 hashing algorithm with the user’s secretKey:

signature=base64.encodestring(hmac.new(secretKey, Parameter_String, hashlib.sha1).digest()).strip().encode(‘utf8′)

signature=GuztixGDmF6W9R6bvKjfV7as05o%3D

4. Generate the Timestamp

The timestamp(_) parameter in the API request is the current system time in milliseconds, not seconds:

_=1386548174877 <== right
_=1383140786        <== wrong

5. The final URL

Once we have all of the above, we can construct the final URL. Note: the Parameter_String (in bold) is the original mixed case string and not the one used to generate the signature:

http://localhost:8080/portal/api/accounts?
_=1386548174877
&apiKey=3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg

&signature=GuztixGDmF6W9R6bvKjfV7as05o%3D

 

API Response Format

To request a specific format, the resource in the API call can be appended with a suffix – .json and .xml which will return JSON and XML respectively.

eg: http://localhost:8080/portal/api/accounts.xml

Alternatively, the BSS API will also support the ‘Accept’ HTTP header to set the format – application/json or application/xml. When both Accept and the suffix are provided, the suffix will take precedence.

eg:  http://localhost:8080/portal/api/accounts
       http-headers = {‘Accept’ : ‘application/xml‘})

In both of the above examples the API response will be in XML. 

 

Sample Python Code: BSS API Request

You will need to replace the apiKey and secretKey values in the code below with your own:

#!/usr/bin/env python
# Author: Tariq Iqbal
#
import urllib2
import urllib
import hashlib
import hmac
import base64
import time
import sys

endpoint=’http://localhost:8080/portal/api’
resource=’/accounts’
timestamp = str(int(round(time.time() * 1000)))

param={}
param['_']=timestamp
param['apiKey']=’3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg’
secretKey=’p5VBDWN7QgrZEfMdSaL7_KN6TQU_1Dfwu5dHqzZ1fBGD_SOjuimuD8VSUND7OKQHvj0oG86WfqrJ6Q-v5P6r1Q’

request_url=”&”.join(["=".join([r,urllib.quote_plus(param[r])]) for r in param.keys()])
# Workout signature
sig_url=resource+”&”.join(["=".join([r.lower(),urllib.quote(param[r]).lower()]) for r in sorted(param.iterkeys())])
sig=urllib.quote_plus(base64.encodestring(hmac.new(secretKey,sig_url,hashlib.sha1).digest()).strip().encode(‘utf8′))

# Build and send API request
url=endpoint+resource+’?'+request_url+’&signature=’+sig
request = urllib2.Request(url, headers = {‘Content-Type’ : ‘application/json’})
try:
        response = urllib2.urlopen(request)
except urllib2.URLError as e:
        if hasattr(e, ‘reason’):
                print ‘We failed to reach a server.’
                print ‘Reason: ‘, e.reason
        elif hasattr(e, ‘code’):
                print ‘The server couldn\’t fulfill the request.’
                print ‘Error code: ‘, e.code
else:
        print “Url: “, response.geturl()
        print “Code: “, response.code
        print “Response: “, response.read()

 

Sample Groovy/Java Code: BSS API Request

You will need to replace the apiKey and secretKey values in the code below with your own.

Thanks to Jamshid Afshar for the following code:

#!/usr/bin/env groovy
// One way to install groovy:
// $ curl -s get.gvmtool.net | bash
// $ logout
// $ gvm install groovy
//
@Grab(group=’commons-codec’, module=’commons-codec’, version=’1.3′)
@Grab(group=’org.codehaus.groovy.modules.http-builder’, module=’http-builder’, version=’0.5.2′ )
import groovyx.net.http.*
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import javax.xml.bind.DatatypeConverter;

// CPBM server
def endpoint = ‘http://localhost:8080/portal/api’
def apiKey = ’3JVTagOc6k5RDhw8fMATBLOCcnnrtLBy-BHiMLt9Y94OjYvG3fnS1CsQDxtXia7FfjARhs-qJQt18tU9EYnTsg’
def apiFunc = ‘/accounts.json’
def oparameterString = ‘_=’ + System.currentTimeMillis() + ‘&apiKey=’ + apiKey
def parameterString = oparameterString.toLowerCase()

// from CryptoUtils.java using field.encryption.key
def SecretKey = ‘p5VBDWN7QgrZEfMdSaL7_KN6TQU_1Dfwu5dHqzZ1fBGD_SOjuimuD8VSUND7OKQHvj0oG86WfqrJ6Q-v5P6r1Q’

Mac mac = Mac.getInstance(“HmacSHA1″);
SecretKeySpec keySpec = new SecretKeySpec(SecretKey.getBytes(), “HmacSHA1″);
mac.init(keySpec);
stringToSign = apiFunc + parameterString
println “stringToSign: ${stringToSign}”
mac.update(stringToSign.getBytes());
byte[] encryptedBytes = mac.doFinal();
String signature = URLEncoder.encode(DatatypeConverter.printBase64Binary(encryptedBytes), “UTF-8″)

def fullUrl = endpoint + apiFunc + ‘?’ + oparameterString + ‘&signature=’ + signature
println “url: ${fullUrl}”

def http = new HttpURLClient( url: endpoint )
try {
    def resp = http.request( url: fullUrl, contentType : ContentType.TEXT)
    println “response: ${resp.status}”
    println “response: ${resp.data}”
} catch( ex ) {
    println “error: ${ex}”
    println “error response status: ${ex?.response?.status}”
    println “error response data: ${ex?.response?.data}”

 

BSS API Known Issues

The list of know issues with the BSS API in CPBM 2.1 can be found here:

http://support.citrix.com/proddocs/topic/cpbm-21-map/cpbm-knownissues-con.html

 

Reference

CPBM 2.1 Documentation:

http://support.citrix.com/proddocs/topic/cpbm-21-map/cpbm-main-wrapper-21-con.html

 

Summary

In this blog we have covered the new BSS API available in CPBM 2.1 and resolved the shortcomings in the supporting documentation. The format of a BSS API request was detailed together with the steps required to create such requests including specifying the format for the subsequent API response. For reference, sample code in Python and Groovy/Java was provided for requesting the list of accounts in CPBM.

About the Author

Tariq Iqbal is a Senior Consultant at ShapeBlue, the Cloud Specialists. He has helped build Cloud environments based on Apache Cloudstack, Citrix Cloudplatform and Citrix Cloudportal for customers worldwide and specialises in integrating billing, business and operations systems into Cloud environments.

When not building Clouds, Tariq is one of those unique Brits who prefers throwing an American football than kicking a round ball.