BlackBerry offers multiple SDKs that allow you to integrate with BlackBerry Workspaces. Functionality across these SDKs is similar, allowing you to choose the one that best suits the platform you are developing for. You can choose between directly calling BlackBerry Workspaces REST APIs from your app or making use of the BlackBerry Workspaces Java SDK, BlackBerry Workspaces .NET SDK or BlackBerry Workspaces Android SDK. This blog post will focus on the BlackBerry Workspaces Java SDK.
A common integration point is an automated system that uses BlackBerry Workspaces for secure file storage and sharing. The first action an application needs to perform is authentication. A service account allows the application to authenticate using public and private keys without user interaction and is ideal for this type of application. Let’s take a look at how we could build it.
Create the Keys
The BlackBerry Workspaces Java SDK Developer Guide contains a section to help get us started configuring the service account our application will use. The first step is to create a public and private key. The public key will be configured in BlackBerry Workspaces and private key used by our application. The developer guide has instructions on how to create these keys using OpenSSL and the Java Keytool. Let’s create one using OpenSSL. In the example below <PRIVATEKEY> represents the name of the file where the private key will be stored. <CERTIFICATE> represents the name of the file where the certificate will be stored.
openssl req -newkey rsa:2048 -nodes -keyout <PRIVATEKEY> -x509 -out <CERTIFICATE>
Run OpenSSL again to display the public key.
openssl rsa -in <PRIVATEKEY> -pubout
Create the Service Account
Now that our keys have been created we are ready to create a service account. If you don’t see the options described below, contact your Workspaces Administrator to set this up for you. You must use a Workspaces account that has the “Organization administrator” role or “Super administrator” role to add a service account.
Log into BlackBerry Workspaces as an administrator, click on the gear icon near the top right and choose “Admin console”. Locate and click on “Service Accounts” on the menu on the left and click the + to add a new service account and enter the following information:
- Paste in the public key, making sure to exclude the “BEGIN PUBLIC KEY” and “END PUBLIC KEY” lines.
- Enter the email address of the account to configure as a system account in the “System accounts” field.
- Choose RSA as the Algorithm.
- Click Add.
Once complete, your account should look similar to the following screenshot. Note the issuer ID highlighted in the red box. This ID will be used within our Java application.
Convert the Private Key to PKCS8
The PEM format of the private key created in the previous section is not well supported in Java applications. We can use another OpenSSL command to convert the private key to PKCS8 format for use in our Java application. In the command below IN_FILENAME refers to the private key created in the previous step and OUT_FILENAME the filename of the PKCS8 private key that will be created.
openssl pkcs8 -topk8 -inform PEM -outform DER -in <IN_FILENAME> -out <OUT_FILENAME> -nocrypt
Read the Private Key in Java
At this point we have completed the configuration steps and are ready to move onto some Java coding. The first method we need to create is one that reads in the private key that will be used to authenticate with the server. This is stored in the PrivateKey class that will be used by the BlackBerry Workspaces APIs.
private PrivateKey readKey() { try { //PRIVATE_KEY_PATH refers to the file system location of the private key. byte[] keyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH)); KeyFactory kf = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(keyBytes); PrivateKey privKey = kf.generatePrivate(keySpecPKCS8); return privKey; } catch (Exception ex) { System.out.println("Error reading private key: " + ex.toString()); return null; } }
Logging In
We are now ready to make use of the BlackBerry Workspaces Java APIs to log into BlackBerry Workspaces. The first class to use is APISession:
APISession apiSession = new APISession("https://workspaces.yourDomain.com", "workspaces");
The APISession constructor requires the URL of your BlackBerry Workspaces server and sub domain. The subdomain is the first section of the URL, which is “workspaces” in the example above. We now use apiSession to attempt to log in:
Enums.LoginResult result = apiSession.startSessionWithServiceAccount(EMAIL_ACCOUNT, "com.watchdox.system.431d.2", 10, key, "SHA256withRSA");
EMAIL_ACCOUNT is the email address of the service account user we created previously and the “com.watchdox.system.431d.2” is the issuer. Both of these values can be referenced from the screenshot above (in the “Create the Service Account” section) that showed the newly created service account in the BlackBerry Workspaces Admin console. You’ll need to replace the example values with ones from your server.
The third parameter – 10 – refers to the timeout value for this session. The next parameter “key” is the private key returned from the readKey() method above. SHA256withRSA is the private key encryption method.
The startSessionWithServiceAccount method returns the result from our login attempt. Verify the login was successful and the application is now ready to interact with BlackBerry Workspaces.
if (result == Enums.LoginResult.Success) { //Do something... }
Listing Workspaces
The SDK comes with sample method implementations for many API calls. The code below makes use of them to list the Workspaces (formerly known as rooms) available.
if (result == Enums.LoginResult.Success) { //Do something... WorkspacesExample wex = new WorkspacesExample(apiSession); ItemListJson<WorkspaceInfoJson> roomsJson = wex.listRooms(); List<WorkspaceInfoJson> rooms = roomsJson.getItems(); for (Iterator<WorkspaceInfoJson> iter = rooms.iterator(); iter.hasNext(); ) { WorkspaceInfoJson room = iter.next(); System.out.println("Room name: " + room.getName()); } }
Wrapping Up
At this point you should now have a Java application that is capable of connecting to BlackBerry Workspaces using a service account and listing all available Workspaces. For easy re-use, a complete copy of the application is included below.
package com.blackberry.workspaces.api.sdk.examples; import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Iterator; import java.util.List; import com.blackberry.workspaces.api.sdk.APISession; import com.blackberry.workspaces.api.sdk.Enums; import com.blackberry.workspaces.api.sdk.json.ItemListJson; import com.blackberry.workspaces.api.sdk.json.WorkspaceInfoJson; public class MarksSample { private static final String EMAIL_ACCOUNT = "you@yourDomain.com"; private static final String PRIVATE_KEY_PATH = "path_to_your_key"; public static void main(String[] args) { new MarksSample(); } public MarksSample() { APISession apiSession = new APISession("https://workspaces.yourDomain.com", "workspaces"); PrivateKey key = readKey(); if (key != null) { Enums.LoginResult result = apiSession.startSessionWithServiceAccount(EMAIL_ACCOUNT, "com.watchdox.system.431d.2", 10, key, "SHA256withRSA"); System.out.println("LoginResult = " + result); if (result == Enums.LoginResult.Success) { //Do something... WorkspacesExample wex = new WorkspacesExample(apiSession); ItemListJson<WorkspaceInfoJson> roomsJson = wex.listRooms(); List<WorkspaceInfoJson> rooms = roomsJson.getItems(); for (Iterator<WorkspaceInfoJson> iter = rooms.iterator(); iter.hasNext(); ) { WorkspaceInfoJson room = iter.next(); System.out.println("Room name: " + room.getName()); } } else { System.out.println("Failed to log in."); } } else { System.out.println("PrivateKey was null"); } System.out.println("Done!"); } private PrivateKey readKey() { try { //PRIVATE_KEY_PATH refers to the file system location of the private key. byte[] keyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH)); KeyFactory kf = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(keyBytes); PrivateKey privKey = kf.generatePrivate(keySpecPKCS8); return privKey; } catch (Exception ex) { System.out.println("Error reading private key: " + ex.toString()); return null; } } }