The IBM FileNet Content Manager product is now available as a SaaS offering hosted on AWS. This post discusses authentication for this Content Services on AWS (CSAWS) offering, with a focus on how custom applications can authenticate and then make API calls into CSAWS.
Authentication in CSAWS
In CSAWS, clients must obtain an OIDC token from the Identity Provider (IdP) that is configured for their tenant. A “tenant” is sometimes referred to as a “service instance”, and it corresponds to a FileNet domain, hosted in CSAWS, that is owned by the customer. We’ll call it a “tenant” here. By default, all new CSAWS tenants are configured to use IBMID as their IdP.
The default IdP is very handy for trial configurations (allows a tenant to be created quickly, without having to specify a bunch of fiddly security parameters). However, customers who already have an IdP deployed in their enterprise will probably want to use their own IdP to allow their users to authenticate to CSAWS, without having to create a new account. CSAWS supports modifying a tenant to use a customer provided IdP for this purpose.
A customer provided IdP can use any authentication technology (passwords, hardware security keys, credentials, biometric indicators, etc) or any combination of authentication factors. As long as the authentication process results in a valid JWT OIDC token, then that is fine.
API support in CSAWS
Content Services on AWS supports three different API’s. Each is discussed in the sections below.
Content Services GraphQL API
This is a GraphQL API implemented according to industry standards. It accepts JSON based HTTP requests which specify in detail what data to fetch and/or update, and returns JSON based HTTP results. Clients of the GraphQL API can be implemented in any language. Python, Java, .NET, and Javascript based clients are common, but many others are possible.
For a detailed reference on Content Services GraphQL API development, see:
https://www.ibm.com/docs/en/filenet-p8-platform/5.5.11?topic=applications-content-services-graphql-development
Content Services Java API
This thick client Java API has been in the market since 2007, with many customer and partner based applications using it (in addition to IBM applications). Clients use object oriented classes, which correspond to business objects, to implement their applications. Under the covers, data is sent back and forth to the Content Engine Web Service (a low level web service API).
The jar files for the CE Java API can be downloaded from the Downloads tile on the CSAWS Landing Page. For a detailed reference on the CE Java API, see: https://www.ibm.com/docs/en/filenet-p8-platform/5.5.x?topic=development-content-engine-java-api-reference
Content Services .NET API
Similar to the Java API, the .NET API is an object oriented API which has also been in the market since 2007. It allows development using Microsoft .NET framework languages, like C# and Visual Basic.NET. , with many customer and partner based applications using it (in addition to IBM applications). The .NET API also sends its data across the wire using the Content Engine Web Service.
The DLL files for the CE .NET API can be downloaded from the Downloads tile on the CSAWS Landing Page. For a detailed reference on the CE .NET API, see: https://www.ibm.com/docs/en/filenet-p8-platform/5.5.x?topic=reference-filenetapicore-namespace
Authenticating as a service user in a backend or command line app
One common use case is that of a backend service or command line tool. These types of applications are typically not browser based. In these scenarios, the client typically does not want to, or cannot, run using the identity of an end user. The client also may not be able to obtain an OIDC token easily, since it is not running in a browser. For this use case, customers typically create a service user, and perform work under the identity of that service user. Authentication is typically done using an API key.
To address this use case, CSAWS supports the creation of service users within a tenant, and the creation of an API key for use by the service user.
Creating a Service user for a CSAWS tenant
A tenant administrator can create service users within the CSAWS Landing page, using the following steps:
1. 1) Click on the blue circle icon in the upper right hand corner of the Landing page, and select the “Service IDs and API keys” option from the drop down menu.
2. 2) Click on the “Create service Id” button to create a new Service user.
3. 3) Enter a name for the service user. This should be an alpha-numeric name, beginning with an alphabetic character. Dashes, dots, and underscores are allowed, but no other non-alphanumeric characters are allowed.
4. 4) Choose a role. This must be either Administrator (a user who has administrative access within the tenant) or User (a user with access to business objects, but no administrative access). Note that you can update the permissions granted to your service user later, using the CSAWS Content and access admin tools.
5. 5) Click the Create button to complete the operation.
When you create a service user, a Content Engine Managed user is created within your tenant domain. Any actions taken by the service user will be done as this Content Engine Managed user. The name of your Managed user will be: <service user name>@<sub-domain>.fid Where service user name is the name that you entered when creating the service user, and sub-domain is the sub-domain of your tenant. When you log onto the CSAWS Landing page, you go to https://<your sub-domain>.content.automation.ibm.com/
You should note the generated name of the service user that you just created (i.e. <service user name>@<sub-domain>.fid ), as you will need this to make API calls as this service user. Note that the generated name cannot exceed 80 characters. So take this into account when creating the service user name, especially if you have a long sub-domain value, since that composes part of this generated name, which is also referred to as the service Id.
Note that service users can only be used to make CSAWS API calls. You cannot log into any CSAWS user interface as a service user.
Creating an API key for your service user
Once you have created a service user, you may now create an API key for use by that service user. If your service user does not yet have an API key, then you can create one using the “Generate key” button / menu option. The only input for this operation is an optional Description field.
After you generate an API key, make sure to copy its value, or use the “Download as JSON” option to download the value to a file. Once you close the API key creation dialog, you will not be able to retrieve the API key value again.
Note that while there is no limit on the number of service users that you can create, each service user is limited to a single API key. If you want to change / reset an API key, then delete the current API key and create a new one.
Obtaining a CSAWS JWT using your API key
When the client application needs to make a call to a CSAWS API, it will first obtain an OIDC token. The OIDC token must be in the form of a JSON Web Token (JWT) -which is a long string. The JWT string is not decipherable by a human, but if a developer needs to determine that a JWT is valid and contains the expected data, it can be captured and pasted in the http://jwt.io web site, for validation.
For service users, your application will need to use the API key generated above to obtain an OIDC JWT. The API keys used in CSAWS are generated using IBM API Connect. In order to use an API key, your application must first make an HTTPS request to API Connect, passing in the following HTTP headers:
- · X-IBM-Client-Id – The value of this header should contain the service Id user name (i.e. serviceuser1@mydomain.fid)
- · X-IBM-Client-Secret – The value of this header should contain the API key value
The URL for the API Connect service that is used by the production CSAWS environment is:
https://api-9o4.us-east-a.apiconnect.ibmappdomain.cloud/ibmcontentservices/csprod/<subdomain>/token
Please make sure to replace <subdomain> in the above string, with the sub-domain for your CSAWS tenant.
The response to this request will be JSON containing the JWT generated for your API key. Your code should extract the value of the “token” node in this JSON, which will be the actual JWT. A sample response from the token endpoint of the API Connect service is shown below.
[{“token”:“eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InNlcnZlciJ9.eyJhdWQiOiI4N2EwZDQ2NS1lODZmLTQ0MzgtOGRiNC1iNDllZGE4YjViYWQiLCJncmFudF90eXBlIjoidXJuOmlldGY6cGFyYW1zOm9hdXRoOmdyYW50LXR5cGU6and0LWJlYXJlciIsImdyYW50X2lkIjoiYjM2ODAxZTctZmQ2OS00NjdmLTkwY2UtNTk0YzMzZmNjZWRjIiwidXNlclR5cGUiOiJyZWd1bGFyIiwidW5pcXVlU2VjdXJpdHlOYW1lIjoiNjQxMDA0MTREVyIsInNjb3BlIjoiIiwianRpIjoiRjQ5VWJnUHozdkQ3bFBieFNoWEFGZ0wwdnFPMEt1IiwiY2xpZW50X2lkIjoiODdhMGQ0NjUtZTg2Zi00NDM4LThkYjQtYjQ5ZWRhOGI1YmFkIiwicmVhbG1OYW1lIjoic2VnMy1yb2dlciIsImlzcyI6Imh0dHBzOi8vZWNtLWlibS1kZXYudmVyaWZ5LmlibS5jb20vb2lkYy9lbmRwb2ludC9kZWZhdWx0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZXVzZXIxQHNlZzMtcm9nZXIuZmlkIiwic3ViIjoiNjQxMDA0MTREVyIsImlhdCI6MTY4NzgwNjM2MywiZXhwIjoxNjg3ODEzNTYzfQ.QMpJ6oKowwFGpGmJRWWyVRNil1jd0zgFJ_Rqr844mSLY8vGYsCeZH5KormXi2jlqq8qXOvotLZlTe1MX62yQVuSciMdlCo8_1X3NZ_g0dpCpg7tN7UfWnL3_VGHQdRLBaknM4MHQj6K8fCv3umAkhefBZO-f-bCsj7vDtaO1szBE5YssEH_cBD0QSNjiyoK5Vzyc1_s2yC3-ij_F90ZKHdftNNKNg9Uuna1PL9ZIqP2V_-b-d8205xJB2kqfcGAIrOTH-mDIi6SmOiFzka1UgA83fgmX_3YeKXF-Q0kC6gNQd7b1ctZ22lXPCXNl4WO_IW33gW1cpQ0DZenPYj0sgA”}]
Passing your CSAWS JWT into a CSAWS API
Once the application has the current user’s JWT token in hand, it can pass it into the CSAWS API that it is using. The sections below discuss how that is done for each CSAWS API.
Content Services GraphQL API
Similar to a REST API, the JWT can be passed into the GraphQL API by putting it into the standard HTTP Authorization header as a “bearer token”. The value of the Authorization header will be: “Bearer <your JWT>”.
Note that there are other HTTP headers required to call the Content Services GraphQL Service. A full API key sample python application is available here: https://github.com/ibm-ecm/ibm-content-platform-engine-samples/tree/master/CSAWS/API-key/CS-GraphQL-API-key-Python A full API key sample Java application is available here: https://github.com/ibm-ecm/ibm-content-platform-engine-samples/tree/master/CSAWS/API-key/CS-GraphQL-API-key-Java
The URL for the Content Services GraphQL API for a production CSAWS tenant is (please make sure to replace <sub-domain>, with the sub-domain for your CSAWS tenant):
https://<sub-domain>.content.automation.ibm.com/content-services-graphql/graphql
For more details, please refer to the Content Services GraphQL API documentation here: https://www.ibm.com/docs/en/filenet-p8-platform/5.5.11?topic=applications-content-services-graphql-development
Content Services Java API
To pass your JWT into the CE Java API, use the constructor for the OpenTokenCredentials class (https://www.ibm.com/docs/api/v1/content/SSNW2F_5.5.0/com.ibm.p8.ce.dev.java.doc/com/filenet/api/authentication/OpenTokenCredentials.html). The doAs() method of the OpenTokenCredentials class can then be used to execute code which makes Content Engine Java API calls using the supplied JWT token.
// Create instance of class used to pass OAuth token to WSI requests using CE API
OpenTokenCredentials otc = new OpenTokenCredentials(testUser, oauthToken, null);
// Retrieve the Domain object
PrivilegedExceptionAction<Domain> getDomainPEA = new PrivilegedExceptionAction<Domain>() {
public Domain run() throws Exception
{
try
{
Domain domain = Factory.Domain.fetchInstance(
Factory.Connection.getConnection(myCE_URI), myDomainName, null);
return domain;
}
catch (Exception e)
{
throw new RuntimeException("Unable to get domain", e);
}
}
};
final Domain domain = otc.doAs(getDomainPEA);
A full API key sample application for the CE Java API is located here: https://github.com/ibm-ecm/ibm-content-platform-engine-samples/tree/master/CSAWS/API-key/cejavaapikey
The URL for the CE Java API for a production CSAWS tenant is (please make sure to replace <sub-domain>, with the sub-domain for your CSAWS tenant):
https://<sub-domain>.content.automation.ibm.com/wsi/FNCEWS40MTOM
For more details, see: https://www.ibm.com/docs/en/filenet-p8-platform/5.5.x?topic=authentication-v559-later-single-sign-integrations-via-content-engine-api-bearer-token
Content Services .NET API
To pass your JWT into the CE .NET API, use the constructor for the .NET API OpenTokenCredentials class (https://www.ibm.com/docs/en/filenet-p8-platform/5.5.x?topic=namespace-opentokencredentials-class). The resulting Credentials object can then be passed to the ClientContext.SetProcessCredentials() method, to establish the credentials to be used for subsequent CE .NET API calls.
// Establish the client credentials to be used for future calls
IConnection conn = Factory.Connection.GetConnection(ceURI);
OpenTokenCredentials creds = new OpenTokenCredentials(serviceId, jwtToken, null);
ClientContext.SetProcessCredentials(creds);
// Retrieve the default domain.
IDomain domain = Factory.Domain.FetchInstance(conn, null, null);
The URL for the CE .NET API for a production CSAWS tenant is (please make sure to replace <sub-domain>, with the sub-domain for your CSAWS tenant):
https://<sub-domain>.content.automation.ibm.com/wsi/FNCEWS40MTOM
A full API key sample application for the CE .NET API is located here: https://github.com/ibm-ecm/ibm-content-platform-engine-samples/tree/master/CSAWS/API-key/CE-dotNET-API-key
Authenticating as an end user in a web application
For the use case of an end user web application, the end users should authenticate as themselves (not as service users), using the configured IdP. On their corporate network, users are likely already authenticated, and already have an OIDC token from their IdP available in their browser. This section focuses on that end user web application scenario. Note that this scenario requires that a custom IdP must be configured with the CSAWS tenant.
The web application will use technology specific to the platform and frameworks that the application is developed with, to obtain the current caller’s OIDC token, in the form of a JWT. Once the application has the current user’s JWT token in hand, it can pass it into the CSAWS API that it is using. The logic to pass the token into the CSAWS API’s is the same as in the previous section, unless the application runs in a WebSphere application server.
If the web application runs in a WebSphere Liberty or traditional WebSphere application server, the JWT token can be extracted automatically from the WebSphere JAAS subject after the user has logged on using their IDP. The JWT token can then be sent to CSAWS APIs without using the OpenTokenCredentials class. Just invoke any CE API method and the JWT token is automatically sent with the request. To enable this feature, set the following 2 JVM options in your WebSphere Application server.
· -Dcom.filenet.authentication.wsi.AutoDetectAuthToken=true
· -Dcom.filenet.authentication.wsi.AuthTokenOrder=oidc,oauth
Dealing with token expiration
For long running applications, the application needs to be aware that the OIDC token will expire after a period of time. This is typically 2 hours. The application should keep track of the time that a token was obtained, and make sure to obtain a new token prior to the expiration of the current token.
Summary
After reading this post, you should now know everything that you need to get started writing custom applications using the FileNet Content Engine API's, running against an FileNet domain hosted in IBM Content Services on AWS. Please refer to the links throughout this post for further information.