Fixing a major bug in beta software

I’ve been working on my card tracking app for some time. I have been using it for approximately 4 years to track my own holiday cards, so there’s tons of data stored in my alpha and beta version.

Today I finally figured out the last major bug, before I look to posting it to the App Store and it’s a dooosey. It will require that I reenter all the data I have in my local copy. The good news is, this will be a major test of how much easier the app is now compared to when I first started using it.

The bug is a very simple uninitialized value on the initial save. I forgot to set the UUID of the recipient and of the card itself. This was causing all kinds of strange behavior later in the app.

Debugging Camera Issues

I’ve been using my Card Tracking App in ernest lately, and have come a cross a strange bug. When I am taking a picture with the camera of a card from within the app, saving the card event occurs, but the image is not saved, while sometimes the whole save fails. This seems to have started with the latest iOS updates (iOS 15.4).

Today I am hoping to be able to figure out if this is a problem with my camera picker or with the save function. The reason this is a big issue for me is that when I changed my card list to a card grid, I lost the ability to delete event records for now. This means I am having a bunch of erroneous entries in the recipient card view.

I need to resolve both of these issues before I start thinking about adding in the card classifier I’ve been working on.

A Beatles’ Retrospective

I’ve been taking some much needed time off, having not been able to take some of my corporate vacation last year. During this time, I am watching the Beatle’s Get Back documentary directed by Peter Jackson.

I’ve always liked their music, and have enjoyed watching the back room machinations of their time in 1969.

I can tell that I’ve been working in an Agile world, when I came to the realization that almost every day the Beatles did a retrospective. They looked at what went well during their session that day, what they may focus on the next day, and what they have learned.

They also started each day easing their way into all the challenges coming up, sitting around and talking. Was this a seated “Stand Up?”

Getting a resource shape

Now that we have a basic understanding of the RootServices document, and how to access protected APIs.  Let’s go thru the process of discovery, in order to identify what is needed for OSLC APIs. I’ll be covering the basics behind the OSLC Resource Shape. Understanding resource shapes is key for identifying what properties are required when creating new components and artifacts with ELM APIs.

Sample Project

I’ve setup a sample project area on the server called “JKE Banking” utilizing the admin screen.

JKE Banking Project Area

I will be using this Project-Area for many of the examples in this series, I recommend setting it up on your development server so that you can follow along.

I’m going to start by looking at a key item for all ELM applications – the Project Area.  To find the services related to Project Areas, we need to look at the OSLC Services Catalog on our server.  As we are working with a DOORSNext server (AKA rm), we can find search for the API in our RootServices document, by searching for <oslc_rm:rmServiceProviders>.

<oslc_rm:rmServiceProviders rdf:resource="https://elm-t1-rm.fyre.ibm.com:9443/rm/oslc_rm/catalog" />

The rdf:resource is the API we will be calling.

In both of the prior blog entries on Authentication, we ended up getting a list of all the Project Areas on our server. Here’s what that API looks like in Python, utilizing http client:

import http.client

conn = http.client.HTTPSConnection("elmwb.com", undefined)
payload = ''
headers = {
  'OSLC-Core-Version': '2.0',
  'Accept': ‘applications/rdf+xml’,
  ‘Authorization’: ’Bearer 6fT3oSX0mysHiaUJH9sXAdCfIXhrG59rNESdLEaQ'
}
conn.request("GET", "/rm/oslc_rm/catalog", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))

API Documentation – OSLC Catalog

Get: https://server:port/rm/oslc_rm/catalog

Authorization: Bearer Token

Request Headers:

“OSLC-Core-Version”:”2.0”

“Accept”:”applications/json” or “text/turtle” or “applications/rdf+xml

Response Body:

<rdf:RDF
	xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
	xmlns:dcterms="http://purl.org/dc/terms/"
	xmlns:jp="http://jazz.net/xmlns/prod/jazz/process/1.0/"
	xmlns:jazzDisc="http://jazz.net/ns/discovery#"
	xmlns:oslc=“http://open-services.net/ns/core#">

  <oslc:ServiceProviderCatalog rdf:about="https://elmwb.com:9443/rm/oslc_rm/catalog">
    <dcterms:title rdf:parseType="Literal">RMCatalog</dcterms:title>
    <dcterms:publisher rdf:resource="https://elmwb.com:9443/rm/application-about" />
    <oslc:domain rdf:resource="http://open-services.net/ns/rm#" />
    <oslc:serviceProvider>
      <oslc:ServiceProvider rdf:about="https://elmwb.com:9443/rm/oslc_rm/_LgdUMIkaEey3TMAARolZjw/services.xml">
        <dcterms:title rdf:parseType="Literal">JKE Banking (Requirements Management)</dcterms:title>
        <jazzDisc:messageReceiver rdf:resource="https://elmwb.com:9443/rm/web/com/ibm/rdm/web/copyReceiver/CopyHandler.html"/>
        <jp:consumerRegistry rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_LgdUMIkaEey3TMAARolZjw/links"/>
        <oslc:details rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_LgdUMIkaEey3TMAARolZjw"/>
      </oslc:ServiceProvider>
    </oslc:serviceProvider>
  </oslc:ServiceProviderCatalog>
</rdf:RDF>

I’ve simplified the response body to only provide information about our “JKE Banking (Requirements Management)” example project.  This catalog will provide us with the <oslc:details>, note this is within a <oslc:serviceProvider>, which is our next API we will execute.

API Documentation – OSLC Project Area Details

Get: https://server:port/rm/process/project-areas/<Project Area UUID>

Authorization: Bearer Token

Request Headers:

“OSLC-Core-Version”:”2.0”

“Accept”:”applications/json” or “text/turtle” or “applications/rdf+xml”

Response Body:

Response Body:
@prefix acc:     <http://open-services.net/ns/core/acc#> .
@prefix process:  <http://jazz.net/ns/process#> .
@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix jfs_process:  <http://jazz.net/xmlns/prod/jazz/process/1.0/> .
@prefix dcterms:  <http://purl.org/dc/terms/> .
@prefix process_shapes:  <http://jazz.net/ns/process/shapes/> .
@prefix oslc:    <http://open-services.net/ns/core#> .

<https://elmwb.com:9443/rm/process/project-areas/_LgdUMIkaEey3TMAARolZjw>
      a       process:ProjectArea ;
      process:isAccessPublic
              "false"^^xsd:boolean ;
      process:isAccessVisibleToAccessList
              "false"^^xsd:boolean ;
      process:isAccessVisibleToMembers
              "true"^^xsd:boolean ;
      process:summary "JKE Banking (Requirements Management)"^^rdf:XMLLiteral ;
      oslc:archived "false"^^xsd:boolean ;
      oslc:instanceShape process_shapes:ProjectArea ;
      oslc:serviceProvider
              <https://elmwb.com:9443/rm/oslc_rm/_LgdUMIkaEey3TMAARolZjw/services.xml> ;
      acc:accessContext <https://elmwb.com:9443/rm/acclist#_LgdUMIkaEey3TMAARolZjw> ;
      dcterms:description "The purpose of this project is to specify and manage the requirements of the JKE Business Recovery Matters project."^^rdf:XMLLiteral ;
      dcterms:modified "2022-02-08T20:04:05.000Z"^^xsd:dateTime ;
      dcterms:title "JKE Banking (Requirements Management)"^^rdf:XMLLiteral .

<https://elmwb.com:9443/rm/application-about>
      a       oslc:Publisher ;
      oslc:icon <https://elmwb.com:9443/rm/web/com.ibm.rdm.web/pages/images/RDNG_16.png> ;
      oslc:label "Requirements Management" ;
      dcterms:identifier "http://jazz.net/application/rm" ;
      dcterms:title "Requirements Management"^^rdf:XMLLiteral .

<https://elmwb.com:9443/rm/oslc_rm/_LgdUMIkaEey3TMAARolZjw/services.xml>
      a       oslc:ServiceProvider ;
      jfs_process:globalConfigurationAware
              "no"^^rdf:XMLLiteral ;
      oslc:details <https://elmwb.com:9443/rm/process/project-areas/_LgdUMIkaEey3TMAARolZjw> ;
      oslc:publisher <https://elmwb.com:9443/rm/application-about> ;
      oslc:service
              [ a       oslc:Service ;
                oslc:domain <http://open-services.net/ns/rm#>
              ] .

Now we are getting somewhere.  The above “text/turtle” response provides us with the “oslc:instanceShape”, this is the description of a “Project Area”.  We can now define what is required in order to create a new project area.  If you haven’t read up on Turtle (https://www.w3.org/TR/turtle/), the above highlighted value tell you that you can go to http://jazz.net/ns/process/shapes/ProjectArea to see it’s resource shape.

Project Area Resource Shape

Currently on the referred page, we see to definition files, one is a RDF/XML file and the other is a Turtle.

Reading the resource shape

Let’s review the turtle, as its format is more human readable.  I won’t go thru the entire file, but will focus on a few entries to help your understanding of an OSLC resource shape.  I purposely chose the Project Area resource shape, as it is a standard resource shape regardless of the ELM server instance.  Please note, there is no public API to create a project area.

Comments and Prefixes
# Arthur Ryman
# 2015-02-25 - Created.
# 2015-03-01 - Improve title. Mark collection resources as hidden. Added instanceShape, accessControl, and accessContext.
# 2015-03-02 - Updated based on review comments from Kevin Cornell and Rafik Jaouani.

@prefix acc: <http://open-services.net/ns/core/acc#> .
@prefix acp: <http://jazz.net/ns/acp#> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix oslc: <http://open-services.net/ns/core#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

@prefix process: <http://jazz.net/ns/process#> .
@prefix shapes: <http://jazz.net/ns/process/shapes/> .

The above lines provide with the various name spaces (or prefixes), this values are used to replace the content in the following lines, e.g. replace acc with the value https://open-services.net/ns/core/acc# so that you can get a fully qualified link to additional information. 

@base <http://jazz.net/ns/process/shapes/ProjectArea> .

<> 
	a oslc:ResourceShape ;
	dcterms:title "Jazz Foundation Project Area."^^rdf:XMLLiteral ;
    dcterms:description "This shape describes project area resources hosted by the Jazz Foundation Process component."^^rdf:XMLLiteral;
    oslc:describes process:ProjectArea ;
	oslc:property
		<#accessContext> ,
		<#accessControl> ,
		<#admins> ,
		<#archived> ,
		<#description> ,
		<#history> ,
		<#instanceShape> ,
		<#isAccessPublic> ,
		<#isAccessVisibleToAccessList> ,
		<#isAccessVisibleToMembers> ,
		<#isInitialized> ,
		<#links> ,
		<#members> , 
		<#modified> ,
		<#projectAdmins> ,
		<#readAccessList> ,
		<#roles> ,
		<#summary>,
		<#teamAreas> ,
		<#timelines> ,
		<#title> .

These lines provide you with the various properties of the resource shape.  We see that we have a “Jazz Foundation Project Area” with 21 properties, beginning with #accessContext and ending with #title.  The remainder of the turtle will describe each of the properties in more detail.

I will review two of the properties “#description” and “#history”.

#description

This is an optional value based on the oslc:occurs being oslc:Zero-or-one.  We can see that XMLLiteral is defined at http://open-services.net/ns/core#valueType as a URI that indicates a value type, in our case XMLLiteral.

<#description>
	a oslc:Property ;
	oslc:propertyDefinition dcterms:description ;
	dcterms:description "The description of the project area."^^rdf:XMLLiteral ;
	oslc:name "description" ;
	oslc:occurs oslc:Zero-or-one ;
	oslc:valueType rdf:XMLLiteral .
#history

This is a mandatory value based on the oslc:occurs being oslc:Exactly-one; however, it is also oslc:readOnly true, meaning that if not provided at create time, then it will not be writable via API.  We can see that it is defined at http://open-services.net/ns/core#valueType as a RDF description, in our case oslc:Resource.

<#history> 
	a oslc:Property ;
	oslc:propertyDefinition process:history ;
	dcterms:description "The link to the history of the project area."^^rdf:XMLLiteral ;
	oslc:name "history" ;
	oslc:occurs oslc:Exactly-one ;
	oslc:representation oslc:Reference ;
	oslc:readOnly true ;
	oslc:valueType oslc:Resource ;
	oslc:hidden true ;
	oslc:range process:History .

A more detailed review of each of the values in the resource shape can be found at the following link.

What is required in the API call?

Now that we understand how to read the resource shape, let’s do an exercise to define what the body of a NON-EXISTENT create Project Area API could look like. After going thru the entire resource shape, you will find 15 values which are listed as “Exactly-One”, these are required for the creation of a new Project Area; however, not all of them are required when calling the API. There are 5 values of “Zero-or-One”, these are optional values, and one value of “Zero-or-Many”, which is an optional list of values.  For most APIs, utilizing the definitions of the properties with “Exactly-One” should provide you with what you need to create a new instance of that Resource.

If you go back to your server and look at the Project Area Definition, we should be able to map to our properties:

Project Area Definition

We can take the list of properties and see the following categories, which could help us in defining the Body of an API call.

Propertyoslc:occursoslc:readonlyoslc:hiddenComments
#accessContextZero-or-manyTRUETRUE
#accessControlZero-or-oneTRUETRUEDeprecated
#adminsExactly-oneTRUETRUE
#archivedExactly-one

Defaults to False
#descriptionZero-or-one

Optional
#historyExactly-oneTRUETRUE
#instanceShapeZero-or-oneTRUETRUE
#isAccessPublicExactly-one

Defaults to False
#isAccessVisibleToAccessListExactly-one

Defaults to True
#isAccessVisbleToMembersExactly-one

Defaults to True
#isInitializedZero-or-one
TRUEDefaults to True
#linksExactly-oneTRUETRUE
#membersExactly-oneTRUETRUE
#modifiedExactly-one

Defaults to create time
#projectAdminsExactly-oneTRUETRUEDeprecated, replaced by #admins
#readAccessListExactly-oneTRUETRUE
#rolesExactly-oneTRUETRUE
#summaryZero-or-one

Optional
#teamAreasExactly-oneTRUETRUE
#timelinesExactly-oneTRUETRUE
#titleExactly-one

Mandatory
Table of Key Property attributes

Given the above table analysis, it would appear that the body of the Create API should contain the following values:

  • A mandatory flag to indicate if the project area is archived
  • An optional description
  • A mandatory flag if it is accessible to the public
  • A mandatory flag if the access is visible to the access list
  • A mandatory flag if the access is visible to members of the project area
  • A mandatory time stamp for the modified time
  • An optional summary
  • A mandatory Title

One thing to consider, the oslc:hidden tag is defined as “A hint that indicates that property MAY be hidden when presented in a user interface.”  Given this, it is likely that you do not need to provide values to a hidden property in an API call, as it is likely to be a computed property.

In my next article I will take a look at a public API and see if we can perform the same analysis to identify the content of the API payload.

API Authentication Method in ELM – OIDC

Security and ELM

In my last post I took you thru the OAuth 1.0a API flow.  While there are three APIs defined in the RootServices document which enable you to execute the flow, it is still a lot of work to ultimately get your OAuth 1.0a Token for usage.  This token is only valid for a short period of time, meaning your code need to constantly check for its availability, and once it fails, you need to process the same steps again to gain a new token.

Now let’s look at using OIDC authentication. 

Initial Setup

First, our ELM instance must be configured to utilize a Jazz Authentication Server (JAS).  That configuration is beyond the scope of this blog, but I highly recommend Shubjit Naik’s article on ELM and OAuth 2.0 Server to Server communication via Client Credentials Grant.

After following those instructions, your ELM Admin will have to provide you with key information to be used in this flow.

  • grant_type
  • client_id
  • client_secret
  • scope

Requesting a Token

As you may recall from the prior post, the RootServices document holds the information we need for OAuth 1.0a authentication; however, this does not hold true for OIDC.  You will need to get the URL for the “access token request” end point from your ELM application admin.  The endpoint can be found via the Server admin page, under the “The Authorization Server”

ELM Server Status Summary

If we add /token to the end of the above URL, we now have the request Token API endpoint.

Request Token API on JAS server

You can see the API is very simple.  We are passing the a grant request of “client_credentials”, with a client_id of “secret2” (which our ELM admin setup for us), a client_secret of “secret”, and asking for scope of “openid profile email general”.  These are all encoded in a url form.  The response that comes back is a simple json, as follows:

{
    "access_token": "6SnfUJgdMFHb4bj5Z6XO65Ay2bGidMfvDWmpgiLu",
    "token_type": "Bearer",
    "expires_in": 7200,
    "scope": "general openid profile email"
}

We receive a “Bearer” token, which expires in 7200 seconds.  It also confirms the scope we have asked for.  

Calling a protected API

Next we will call an API that requires authentication.  I will use the same API from the prior post, accessing a list of Project Areas on our server.

curl --location --request GET 'https://elmwb.com:9443/rm/process/project-areas' \
--header 'OSLC-Core-Version: 2.0' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer 6SnfUJgdMFHb4bj5Z6XO65Ay2bGidMfvDWmpgiLu

As you can, all we did is change our call to provide the authorization via a new header. This is much easier (and quicker) than the steps required in OAuth1.0a.

If you are familiar with Postman, here are two files to help you process these same steps:

Postman Environment File – OIDC Demo Environment

Postman API Collection – OIDC Flow

That’s it!  If you have the opportunity on your server to setup the Jazz Authentication Server, I highly recommend that you utilize OIDC for your API which require authentication.

API Authentication Method in ELM – Oauth 1.0a

The goal of the next two posts is to provide you with methods for authentication of your APIs.  I will not be going thru all the methods that a ELM server support authentication, but at a high level your server can either be setup to use application level authentication or to delegate that authentication to some external service.  If you utilize application level authentication your APIs should be using OAuth 1.0a. If you utilize delegated authentication, you will be using a Bearer token with your APIs.

Let’s begin with OAuth 1.0a:

As I pointed out in the blog post on “Beginning API Discovery”, each server exposes a set of key end points which are required as part of OAuth.  Before using those APIs we will need to access our server as an admin and create a key / secret pair, with the appropriate access we will need for our APIs.  

  1. We will log in as elmadmin (utilize an appropriate user ID with server administrative authority on your server), on our Requirements Management Server, and access the Server Admin page.
https://elmwb.com:9443/rm/admin
  1. Select Consumers to access the OAuth Consumers page. At the top of the page we will register a new “Oauth Consumer” and the system will generate a key for us.  We need to provide the following information:  consumer name (this is informational only), a consumer secret (which will be used as part of our OAuth1.0a process), and select trusted.
Server -> Consumers (Inbound)
  1. The system will provide you with the Consumer Key, but you still need to assign a functional user ID. To assign the ID go to the bottom of the page and select the pencil (edit) under actions, and then choose “Select User”.  Search for and select the appropriate user id (elmadmin on my server), choose OK, and select Finish.
Creating a new Consumer
Editing to add User
Search and Select User
  1. Your server is now set and you have all the information to actually authenticate your API calls to the ELM server utilizing OAuth 1.0a.  If you don’t have authority to do the above steps, you will need to work with your server administrator who will provide you with the Consumer Key and Secret, you will need to use in authentication before you API can use OAuth.

What is OAuth?

OAuth is a standard for allowing access to protected resources without disclosing user credentials.  OAuth is defined at https://oauth.net/core/1.0a/ and consists of three steps (as defined in section 6 of the previous link).  For this purposes of this post, I will assume that you have read thru the details of OAuth and are looking for a practical approach of how to implement it with your API flow.

Remember our RootServices

In a prior blog post (Beginning API Discovery) I pointed out the following information being provided in the RootServices document:

<jfs:oauthDomain>https://elmwb.com:9443/jts,https://elmwb.com:9443/rm</jfs:oauthDomain>
<jfs:oauthRealmName>Jazz</jfs:oauthRealmName>
<jfs:oauthAccessTokenUrl rdf:resource="https://elmwb.com:9443/jts/oauth-access-token" />
<jfs:oauthApprovalModuleUrl rdf:resource="https://elmwb.com:9443/jts/_ajax-modules/com.ibm.team.repository.AuthorizeOAuth" />
<jfs:oauthExpireTokenUrl rdf:resource="https://elmwb.com:9443/jts/oauth-expire-token" />
<jfs:oauthRequestConsumerKeyUrl rdf:resource="https://elmwb.com:9443/jts/oauth-request-consumer" />
<jfs:oauthRequestTokenUrl rdf:resource="https://elmwb.com:9443/jts/oauth-request-token" />
<jfs:oauthUserAuthorizationUrl rdf:resource="https://elmwb.com:9443/jts/oauth-authorize" />

For our API process we need three key end points – <jfs:oauthAccessTokenUrl>, <jfs:oauthRequestTokenUrl>, and <jfs:oauthUserAuthorizationUrl>. These API end points support our process as defined above in the OAuth standard link.

There are many libraries and other tools which may make it easier for you to deal with OAuth; however, I’d like to take you thru the entire flow in this post.  This will help you understand how the APIs work, that you just discovered in the RootServices API.

High-level OAuth Flow


Simplified Oauth 1.0a Flow

It looks pretty easy doesn’t it?  Seriously, it will take a bit to break it down.  Using our specific APIs from the RootServices document, I’ll also show you the headers, and how the redirects work.

Step 1 – We begin with the initial Post in the top left of the above image.  This maps to section 6.1 in the Oauth specification for obtaining an unauthorized Request Token.  This token can only be used once, and requires providing your oauth consumer key, oauth consumer secret, a signature method, oauth signature, and a oauth nonce.  We support HMAC-SHA1 for the signature method.  Creating your oauth signature is defined in section 9.1 of the above Oauth standard.  The nonce, is any unique value you wish to provide, as nonce means – “number used once”,  a full time stamp usually works fine for this.

curl --location --request POST ‘https://elmwb.com:9443/jts/oauth-request-token?oauth_consumer_key=92cd70d34ec442329b5651d3d50bfa76&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1645136440&oauth_nonce=HCkegHwV6nx&oauth_signature=RU29jNzYtT%2FLKBOQEjVmfa2FVeg%3D'

As you can see from the above CURL command, I am passing a consumer key of 92cd70d34ec442329b5651d3d50bfa76. My secret was used in the encoding of the signature.   

The response is very simple: 

oauth_token=b87ebfa4fc934690b561720ae6e3af10&oauth_token_secret=B3tvnNvd1xeT1mZ2Fcz0EAQkDI1kmp487lCfGOlrDLM

As you can see I am returned an unauthorized Token and Secret, which I will use in the next step.

Step 2 – Now that we have our unauthorized token, we need to exchange it for an authorized token.  This is our <jfs:oauthUserAuthorizationUrl> API, again from our RootServices document.  We will pass the oauth_token we received in the prior step, to get a authorized token and secret. 

curl --location --request GET 'https://elmwb.com:9443/jts/oauth-authorize?oauth_token=9bef1a97db994466a79930d769cb0f7f'

This will begin a series of redirects (Status code 302) that we will want to follow-until we execute an authorization request from the client application.  This allows for the client to provide the authentication, indicating your credentials are authorized.  Let’s go thru the redirects to understand what is going on.

Key response headers:

X-com-ibm-team-repository-web-auth-msg: authrequired
Location: https://elmwb.com:9443/jts/secure/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3Db25d99ad678f47e99daa4d20be21ab63

To process this redirect, I will perform a GET against the value provided by the location header:

curl --location --request GET 'https://elmwb.com:9443/jts/auth/authrequired' \
--header 'Accept: application/rdf+xml’

This will provide a second redirect (Status code 302), along with the following key response header:

Location: https://elmwb.com:9443/jts/auth/authrequired

Once again, we take the location and execute another GET looking for a Status code of 200, and the “X-com-ibm-team-repository-web-auth-msg with the message ‘authrequired’”.

curl --location --request GET 'https://elmwb.com:9443/jts/auth/authrequired'

We can now perform the appropriate user authentication required by our server.  On my ELM server the API end point is j_security_check, this will not be the case if you are using a different server to authenticate your user id.

curl --location --request POST 'https://elmwb.com:9443/rm/j_security_check' \
--header 'oauth_token: 9bef1a97db994466a79930d769cb0f7f' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'j_username=elmadmin' \
--data-urlencode 'j_password=elmadmin'

As you can see the above API, I am passing an encoded form with the user id and password, along with the header, which includes my authorized oauth_token.  Our response should be another redirect (302), with a location header containing the redirect we will follow:

https://elmwb.com:9443/jts/secure/authenticated/identity?redirectPath=%2Fjts%2Foauth-authorize%3Foauth_token%3Dd73245874ae24736ac54b4d99cbe8536

This redirect will provide us with the URL of the Oauth-Authorize function, with the original unauthorized Oauth Request token from Step 1.  We will follow the redirect and related response location header, until we receive a Status code of 200.  On my server this takes two calls.  The final call provides a response explaining what authentication I have:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>OAuth Consumer Authorization</title>
        <link rel="stylesheet" type="text/css" href="web/com.ibm.team.repository.web/ui/oauth/templates/Authorize.css" />
        <script language="JavaScript" src="web/com.ibm.team.repository.web/ui/oauth/Authorize.js"></script>
    </head>
    <body>
        <div class="boxDiv">
            <div class="content">
                <div clas="header">
                    <h4>You have allowed the server &quot;elmadmin&quot; to collaborate with the server &quot;https://elmwb.com:9443/jts/&quot; using the &quot;elmadmin&quot; user ID.  </h4>
                </div>
            </div>
        </div>
    </body>
</html>

Step 3 – At this point, you call the third API identified in the RootServices document – <jfs:oauthAccessTokenUrl>. Which will provide you with an authenticated token and secret.

curl --location --request GET 'https://elmwb.com:9443/jts/oauth-access-token' \
--header 'Authorization: OAuth oauth_consumer_key=“b20fa15ba1d94a26a62f484b3bf701f9",oauth_token="d73245874ae24736ac54b4d99cbe8536",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1645540874",oauth_nonce="pi6DEJIQwVm",oauth_signature="%2Fyaxha74xspsecKRNWKsOigShSA%3D"

As you can see I am passing my consumer Key and my original token (which has been authenticated).  The response back is simply:

oauth_token=02334c23bc734c48a519ed75a5359f94&oauth_token_secret=moY6vTLGKkUd3PPlmMTb3X0ApgirO9enXjvOSgEVoI

We are now ready to use our Oauth1.0a credentials.  If we want a list of Project Areas on this sever we would simply provide the following:

curl --location --request GET 'https://elmwb.com:9443/rm/process/project-areas?oauth_consumer_key=b20fa15ba1d94a26a62f484b3bf701f9&oauth_token=02334c23bc734c48a519ed75a5359f94&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1645541598&oauth_nonce=oKMVvxXC0LC&oauth_signature=5HUQG2MJzA%2Bk%2FsbfuLdiGhP2mkQ%3D' \
--header 'OSLC-Core-Version: 2.0' \
--header 'Accept: application/json’

Mapping back to our our above steps we see:

  1. We are using our original Consumer Key from the ELM server
  2. We are using our returned Oauth Token from the response of our third API call above.
  3. The oauth signature method, timestamp, nonce and signature are all created as defined above.

If you are familiar with Postman, here are two files to help you process these same steps:

Postman Environment File – OAuth1.0a Demo Environment

Postman API Collection – OAuth1.0a Flow

Wow!  That was a lot of work.  This post took a lot longer than I expected. There has to be an easier way, and there is!   I will cover that in the next post, on how to use OIDC (OpenID Connect – https://openid.net/connect/ ).

Beginning API Discovery (or understanding the RootServices document)


Photo by Felix Mittermeier on Unsplash

Now that we’ve covered some of the basics on what we mean when we say APIs (link to prior post), it’s time to get into the power of ELM thru its API discovery process.

Many of the APIs on a server are exposed thru API calls.  The foundation of this discovery mechanism is the “RootServices” document of the ELM application.  Each ELM application has its own RootServices document. I’ll be focusing on four of the ELM applications, specifically:

  • JTS – Jazz Team Server
  • CCM – Configuration and Change Management – AKA – Engineering Workflow Management
  • QM – Quality Management – AKA – Engineering Test Management
  • RM – Requirements Management – AKA Engineering Requirements Management or DOORS Next

For the purpose of this series of blog posts, I will be using a locally hosted server named https://elmwb.com on port 9443. You will need to replace this server name and port with the server information of your own.

The RootServices API is publicly addressable; it doesn’t require any authentication.  The reason behind this is to ensure that you can discover the services for authentication, and so that servers can query each other regarding what services are available.  Most APIs that are exposed in the RootServices do require authentication.   I will have two separate blog posts which all address authentication, one covering OAuth1.0a and one covering the use of a Bearer token.

RootServices API

The API for accessing the RootServices document is simply:

GET https://<<SERVER>>/<<APPLICATION>>/rootservices

The API also requires you to include at least one of the following headers in order to define the format of the RootServices document:

	accept:application/rdf+xml
	accept:application/json
	accept:text/turtle

If you use CURL the API call would be:

curl --location --request GET ‘https://elmwb.com:9443/rm/rootservices' \
	--header 'accept: application/rdf+xml'

The flexibility of the response body allows you to introspect the contents in an appropriate manner for your specific needs.  One key difference to note in the formats is that both RDF and Turtle formats provide descriptors to simplify the contents; json does not have descriptors.  In RDF, these descriptors are identified with “xmlns” (or xml name space), while in turtle they are identified with @prefix.  Understanding the rest of the differences between these formats is up to you. More information can be found at:

The following images show the beginning of the RootServices document in the above three formats:

application/rdf+xml
application/json
text/turtle

Let’s look at the overall structure and content of the RootServices document and how it will help us for future APIs.  I will be using the rdf+xml format for the rest of this post.

There are three major sections in the RootServices document:

  1. Name Spaces – the name spaces identify the domain and/or process that governs a specific resource.  Each name space is provided with a short identifier which is used as a prefix for defining the full URI which describes a resource.  For example the identifier xmlns:dc describes the “Dublin Core” term as defined at “http://purl.org/dc/terms/“.  This prefix is then used in the definition of resource called <dc:title>.  The full definition of the title can be found at http://purl.org/dc/terms#title .
Dublin Core term example
  • Understanding the details about “Dublin Core” is not critical to the understanding of the RootServices document; it provides a simple way of explaining the name space concept. If you want learn more about “Dublin Core” you can check out their website at https://dublincore.org.
  1. Comments – In the rdf+xml format these lines are identified as <!— —> and are informational only.
  1. Resources – This section describes the name spaces for the server. By placing the service in this RootServices document this can be considered public APIs.  The name space prefix defined earlier in the RootServices document can provide you context about which aspect of the server the specific service addresses.  Some general guidelines include:
  • jd = Jazz Discovery
  • jfs = Jazz Foundation 
  • jdb = Jazz Dashboard
  • ju = Jazz UI elements
  • jp06 = Jazz Process (release 0.6)
  • jp = Jazz Process (release 1.0)
  • oslc = Open Services for Lifecycle Collaboration – this is the Oasis based standard for services across lifecycle based applications.  ELM is both a provider and consumer of OSLC services.  For more information on OSLC and Oasis see: https://open-services.net and https://www.oasis-open.org/ .
  • oslc_XX = OSLC services for a specific application, for example rm = requirements management, cm = change management, etc.
  • rm = Requirements Management, these are DOORS Next specific services
  • trs = Tracked Resource Set version 1.x
  • trs2 = Tracked Resource Set version 2

A detailed (yet somewhat dated) description of the RootServices document can be found on jazz.net at https://jazz.net/wiki/bin/view/Main/RootServicesSpec.

Next, we focus on a few key sections in the RootServices document which will help us discover more APIs as we move forward:

First, after the list of name spaces, we see the Title of the server whose RootServices we are accessing and a detailed description of the server.  They are all in the dc name space, i.e. Dublin Core.

<dc:title xml:lang="en">Doors Next</dc:title>
<dc:description>This application provides the capabilities to create and manage requirements and trace them to modeling, testing, and change and configuration management. You can define, elicit, capture, elaborate, discuss, and review requirements and supporting artifacts.</dc:description>

Second, is a list of common services for the Jazz server and application we are on. Included in this section are those services that are necessary for authentication when using our APIs.

If you are utilizing OAuth1.0a to access the APIs, you should look at the jfs services with include oauth in their name.  On my server, the following services are exposed:

<jfs:oauthDomain>https://elmwb.com:9443/jts,https://elmwb.com:9443/rm</jfs:oauthDomain>
<jfs:oauthRealmName>Jazz</jfs:oauthRealmName>
<jfs:oauthAccessTokenUrl rdf:resource="https://elmwb.com:9443/jts/oauth-access-token" />
<jfs:oauthApprovalModuleUrl rdf:resource="https://elmwb.com:9443/jts/_ajax-modules/com.ibm.team.repository.AuthorizeOAuth" />
<jfs:oauthExpireTokenUrl rdf:resource="https://elmwb.com:9443/jts/oauth-expire-token" />
<jfs:oauthRequestConsumerKeyUrl rdf:resource="https://elmwb.com:9443/jts/oauth-request-consumer" />
<jfs:oauthRequestTokenUrl rdf:resource="https://elmwb.com:9443/jts/oauth-request-token" />
<jfs:oauthUserAuthorizationUrl rdf:resource="https://elmwb.com:9443/jts/oauth-authorize" />

We see three key end points which are necessary for a OAuth1.0a process (which I will cover in detail in another blog post) – oauthAccessTokenUrl, oauthRequestTokenUrl, and oauthUserAuthorizationUrl.  These three URLs are needed to address the three steps that a OAuth authentication that I will cover in another blog post.  

Third, is a list of application specific services.  On our sample server, which is Doors Next application server, we see the following list of services.

<!-- Applications may add any services they provide here -->
<oslc_rm:rmServiceProviders rdf:resource="https://elmwb.com:9443/rm/oslc_rm/catalog" />
    <oslc_rm:majorVersion>7</oslc_rm:majorVersion>
    <oslc_rm:version>7.0.2</oslc_rm:version>
    <oslc_rm:buildVersion>7.0.2</oslc_rm:buildVersion>
    <oslc_config:cmServiceProviders rdf:resource="https://elmwb.com:9443/rm/oslc_config"/>
    <rm:glossaryTermsQuery rdf:resource="https://elmwb.com:9443/rm/glossary/termslookup" />
    <rm:components rdf:resource="https://elmwb.com:9443/rm/cm/component/ldpc" />
    <rm:projectAreas rdf:resource="https://elmwb.com:9443/rm/projects" />
    <rm:cmpProjectAreas rdf:resource="https://elmwb.com:9443/rm/rm-projects" />
    <rm:rrcExtensions>0.1.3-0.1.5</rm:rrcExtensions>
<!-- The admin Web UI service should be uncommented in applications -->
    <jfs:adminWebUI rdf:resource="https://elmwb.com:9443/rm/admin" />
<!-- The registration handler service should be uncommented for application  that do not supply their own -->
    <jd:registration rdf:resource="https://elmwb.com:9443/rm/service/com.ibm.team.repository.service.internal.setup.IRegistrationHandlerService" />
<!--  Process Component Tracked Resource Set 2.0 Provider -->
    <rm:trackedResourceSetProvider>
        <trs2:TrackedResourceSet>
            <trs2:trackedResourceSet rdf:resource="https://elmwb.com:9443/rm/process-trs2" />
            <dc:title>TRS 2.0 for DOORS Next Process Resources</dc:title>
            <dc:description>TRS 2.0 feed for process resources in DOORS Next</dc:description>
            <dc:type     rdf:resource="http://jazz.net/ns/process#" />
            <oslc:domain rdf:resource="http://jazz.net/ns/process#" />
        </trs2:TrackedResourceSet>
    </rm:trackedResourceSetProvider>
<!-- End of application-specific services -->

As you can see this server has OSLC and RM specific services.  We also see that this server is a TRS 2.0 provider. 

Key for our discovery of APIs, we would want to look at the oslc:rmServiceProviders.  A GET to this API will provide us with a catalog of those objects that provide services.  In the case of this server it will be a catalog of the Project areas on our server, along with the services they provide.

Let’s do a quick GET call to the API identified in oslc:rmServiceProviders.  If you are trying this via a browser, you will get prompted for a log in, this tells us that the API needs to be authenticated.  Go ahead and log in and look at the results.  On my server I have setup three Project areas, and it will provide us with the following response:

<rdf:RDF
 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 xmlns:dcterms="http://purl.org/dc/terms/"
 xmlns:jp="http://jazz.net/xmlns/prod/jazz/process/1.0/"
 xmlns:jazzDisc="http://jazz.net/ns/discovery#"
 xmlns:oslc="http://open-services.net/ns/core#">

 <oslc:ServiceProviderCatalog rdf:about="https://elmwb.com:9443/rm/oslc_rm/catalog">
    <dcterms:title rdf:parseType="Literal">RMCatalog</dcterms:title>
    <dcterms:publisher rdf:resource="https://elmwb.com:9443/rm/application-about" />
    <oslc:domain rdf:resource="http://open-services.net/ns/rm#" />
    <oslc:serviceProvider>
      <oslc:ServiceProvider rdf:about="https://elmwb.com:9443/rm/oslc_rm/_LgdUMIkaEey3TMAARolZjw/services.xml">
         <dcterms:title rdf:parseType="Literal">JKE Banking (Requirements Management)</dcterms:title>
         <jazzDisc:messageReceiver rdf:resource="https://elmwb.com:9443/rm/web/com/ibm/rdm/web/copyReceiver/CopyHandler.html"/>
         <jp:consumerRegistry rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_LgdUMIkaEey3TMAARolZjw/links"/>
         <oslc:details rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_LgdUMIkaEey3TMAARolZjw"/>
      </oslc:ServiceProvider>
    </oslc:serviceProvider>
    <oslc:serviceProvider>
      <oslc:ServiceProvider rdf:about="https://elmwb.com:9443/rm/oslc_rm/_VoWUwIkbEey3TMAARolZjw/services.xml">
         <dcterms:title rdf:parseType="Literal">Sample Project 1 (Requirements)</dcterms:title>
         <jazzDisc:messageReceiver rdf:resource="https://elmwb.com:9443/rm/web/com/ibm/rdm/web/copyReceiver/CopyHandler.html"/>
         <jp:consumerRegistry rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_VoWUwIkbEey3TMAARolZjw/links"/>
         <oslc:details rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_VoWUwIkbEey3TMAARolZjw"/>
       </oslc:ServiceProvider>
    </oslc:serviceProvider>
    <oslc:serviceProvider>
    <oslc:ServiceProvider rdf:about="https://elmwb.com:9443/rm/oslc_rm/_BVnHAImtEeyjbIIiaev_dg/services.xml">
       <dcterms:title rdf:parseType="Literal">Title test</dcterms:title>
       <jazzDisc:messageReceiver rdf:resource="https://elmwb.com:9443/rm/web/com/ibm/rdm/web/copyReceiver/CopyHandler.html"/>
       <jp:consumerRegistry rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_BVnHAImtEeyjbIIiaev_dg/links"/>
       <oslc:details rdf:resource="https://elmwb.com:9443/rm/process/project-areas/_BVnHAImtEeyjbIIiaev_dg"/>
    </oslc:ServiceProvider>
  </oslc:serviceProvider>
</oslc:ServiceProviderCatalog>
</rdf:RDF>

I am not going to go through all the details right now, but just realize we have a list of all the project areas (or Service Providers) on this server.  We can actually execute a GET against a specific project area to get a list of supported services for that Project area.  This can be found in the <oslc:ServiceProvider > section.  But that’s for another blog post.

API types and the API Landing Page

When someone mentions APIs what do you think of?  Let’s look at the acronym and the discuss how I will be using it over the course or this blog series. 

API Blackboard

API stands for “Application Programming Interface”.  This term is pretty broad as it is a connection between computers, programs and software services. APIs can be pubic or private, supported or unsupported.  I will only be talking about Public / supported APIs within the scope of our ELM capabilities.

Accessing a specific API can be done via a SDK (software development kit) or via Rest APIs (Representational state transfer ). I will begin with focusing on Rest API.

IBM ELM API Landing page

Jim Ruehlin & Rosa Naranjo have created a landing page that consolidates all the existing API documentation available across jazz.net (link).  This page provides grouping of existing APIs (both Rest and SDK based APIs), along with how to guides.  One thing to notes is this page references “CLM”.  CLM stands for Collaborative Lifecycle Management ( this is a legacy name for our IBM Engineering Lifecycle Management applications). 

As a developer, we all have an innate definition of what an API is. An API is how we access some function of an application.  APIs are exposed in SDKs (Software Development Kits), compiler or language libraries, and services.  I am going to focus this set of blog posts on service based APIs.  ELM utilizes a standards based Service Oriented Architecture called OSLC.  OSLC or Open Services for Lifecycle Collaboration is specifically designed to address the software development process, utilizing a SOA approach. As such, the API end points and payload requirements are discoverable via services.  I’ll be going thru this discovery process over a few blog posts.

However, let’s start with a quick review of our existing API Landing page and the menu on the right hand side.  As you can see we have sections for basic concept, each of the applications and developing java applications.

OSLC

General OSLC and CLM API information – The foundation for many of our APIs in ELM is OSLC.  OSLC is an open standard for defining messages and APIs across various lifecycle processes.  Getting a good understanding of OSLC is key for many of the topics we will discuss going forward.

Jazz Foundation

Jazz Foundation – Many of the ELM applications are built on top of our Jazz platform.   This foundational component supports a set of common APIs that should be the same regardless of the application you are working with.

Managing Variants

Global Configuration Management – One of the most powerful features of IBM ELM is Global Configuration Management or GCM.  GCM allows you to assemble configurations from across ELM applications.  These Global Configs (GCs) can be reused in different versions or variants of software and product lines. GCM supports the OSLC APIs, a set of Rest API and a Client Extension SDK.

DOORS Next – Requirements management (AKA – DNG) allows for capturing, tracing, analyzing, and managing changes to requirements. There are many different API models that are supported by DNG include OSLC, both client and server SDKs, and Rest APIs for Modules, Reports, ReqIf, and other features.

Rational Team Concert (EWM) – Workflow management allows teams to create and manage work plans across multiple development projects utilizing Agile, SAFe (Scaled Agile Framework for Enterprises), or custom processes. The API’s supported by EWM have a lot of coverage in blogs and other resources, including the work of Ralph Schoon. Ralph has been blogging about EWM APIs for over a decade.  Check out his blog at – https://rsjazz.wordpress.com/. EWM has support for OSLC, REST and SDK based APIs.

Rhapsody Model Manager – Architecture Management allows you to manager your models and code on the same configuration management server.  It also provides linkage between requirements and work items across ELM. It provides a set of REST APIs for accessing artifacts for reporting.

Rational Quality Manager (ETM) – Engineering Test Management enables test planning and management supporting test execution, results reporting, and integration with other testing execution applications.  Supporting both OSLC and REST based APIs, you may also create custom test automation adapters via APIs to integrate with third party test execution tools.

Reporting – ELM reporting is supported both by individual applications and across applications via the ELM Report Builder.  This section provides details on LQE (the Lifecycle Query Engine) and Report Builder, along with Reporting APIs for Requirements (DNG), Test (ETM), and Workflow(EWM).

Plain Java Client or Jazz APIs – The above sections will have links to the appropriate plain java client and other Jazz APIs.  This section provides a single place to get to them regardless of application supported.

If you’ve made it this far, you realize there really is a lot of API documentation and content for you to go thru.  But how can you digest it all?  In the next post I’ll take you thru the common entry point for understanding the APIs supported by a specific ELM application – the RootServices document!

Welcome to API Corner

“With Great Power comes Great Responsibility”. I remember first hearing this phrase in Spider Man comics.  But it has a much longer history than that.  Wikipedia indicates that this is actually an ancient phrase going back to the first century BC.  I find that IBM Engineering Lifecycle Management’s (IBM ELM’s)  incredible flexibility and power is a lot like this phrase.

You have great power in integrating the ELM capabilities with other tools and processes, but you are responsible for understanding a lot of basic concepts.

There’s a lot of existing content available on our API page, but it can be overwhelming if you are not familiar with the applications and some basic concept.  So over the course of this blog series I plan on going thru the major APIs across ELM applications, while also explaining some of the basic concepts behind how to understand our APIs.

Having said all this, let me introduce myself.  My name is Michael Rowe, and I’ve been at IBM since 1995.  In that time I’ve had many roles across development, product management, IBM research, services, and strategy.  In my spare time I develop iOS apps for fun, podcast on gaming and technology, swim and sing light opera.  You can follow those topics over at my personal blog – https://michaelrowe01.com. I joined IBM Rational in 2008 and focused on brand level strategy, looking at how we integrate with other IBM brands (like Tivoli), across the development lifecycle (Urban Code for DevOps, WorkLight for Mobile app development), and with business partners.  I moved to IBM research for a few years to help identify technologies which could and should be brought into products, coming back to the Watson IoT business unit in 2017 to help drive strategy.  I have worked with business partners for a few years and in 2021 came back to my technical roots by joining our ELM Architecture team with a focus on APIs.

I have experienced the same learning curve that many of you will be experiencing as you get started learning how to access and understand our APIs, and as such, we will take this journey together.  My personal approach to learning is to read, in order to understand a concept, and then attempt to validate what I read by performing a simple exercise.  Some of the concepts that we leverage in ELM may require multiple exercises.

My goal is to help you quickly get thru the concepts and find the APIs you need to better leverage the IBM ELM capabilities. Over time, I will be working closely with our product manager, Jim Ruehlin (link – https://jazz.net/wiki/bin/view/Main/JimRuehlin) , to address API documentation and clarity, but more on that in a future post.

I look forward to hearing from you…so let’s get started…

A potential plan for 2022

As I mentioned a while back, I took on a much more technical role in my day job recently. I am working on IBM’s “Engineering Lifecycle Management” product offering as a solution architect. My primary focus is on our reusable components, which includes many of our APIs.

APIs are the building blocks of modern applications, and ELM has had APIs since its foundation many years ago. Many of the APIs are build around the concept of Open-Services for Lifecycle Collaboration or OSLC. The OSLC standard utilizes RDF as the format for its payloads; which is unfamiliar to many people.

RDF allows for a semantically rich representation of data.

Swift Playgrounds

This weekend I wanted to see if I could make a very simple (and quick) iOS application utilizing Swift Playgrounds to read the “root services” document from any ELM application. I had created a iOS app for my own use to do this in the past, utilizing a Swift Package by Gregory Williams called serd-swift. This is a simple wrapper for the fast C library created by David Rollibard – serd.

Of course, like many ideas dreamed up in the shower, this project was not going to be as simple as I wanted. I started by creating a simple iOS app in Swift Playgrounds and adding in the above package. At this point Swift Playgrounds complained that it could not compile “C” code.

The funny thing is that Swift Playgrounds didn’t just come out and say that the Package was the problem, the message showed up as the error – “The target type, “Clang Target”, is not supported. The good news is, I used to write objective C on the Mac, so I knew this meant, the “C” programming Language.

I knew that in advance but had totally forgotten about it. So now my plan is to try to write the original serd library by David into a native Swift Package. This won’t be easy, and I plan to post updates on my blog as I progress.

Stay tuned, as this may take a while.