Publish files to Cornell Box from your application

At RAIS, we recently had a use case for publishing custom PDF reports, generated in python scripts (Pandas + Matplotlib+ WeasyPrint), to a specific set of Cornell users. Our requirements were:

  • Don’t use email
  • Don’t require fileshare access
  • Allow functional users to control the access list
  • Track who accesses the files
  • Be easy to use for all involved

Many of our end-users were already accustomed to using Cornell Box (https://it.cornell.edu/box) and it meets the basic requirements for this use case— however, we had not yet interacted with it programatically. After a few days of effort, I’m happy to say it was very easy to get set up, and the Box team at Cornell was very responsive and helpful. Our approach, as well as the request/approval process, is described below.

The Code

If you’d prefer to start with code, it is posted here: https://github.com/CU-CloudCollab/box-publish-example

Note: you’ll need to go through the setup process below to register your app with Cornell before you can do anything with it.

The code includes example and helper scripts, as well as a small wrapper library for the functions we use often (get aws SSM parameter, get an instance of the box client, and write files to box with support for versioning).


Setting up your App with Cornell

The first step is to create a new app — start by logging into Box and opening the Dev Console:

Next, choose to create a new app:

For this example, we’re using an Enterprise Integration app, so choose that:

Choose OAuth 2.0 with JWT as the authentication method:

Give your app a name:

Limit the scope of your application to what is absolutely necessary — for our use case, publishing to specific folders created by other people, this worked:

Likewise, we didn’t need the following:

Generate a Key Pair:

When you generate the Keypair, Box will prompt to you download a JSON file with all of your app credentials. Save this somewhere safe. We put it into an encrypted SSM parameter in AWS.

Example of the JSON file:

At this point, to proceed any further, you’ll need to submit your application for approval to the Cornell box team. This can be done by opening a ticket with the IT service desk (itservicedesk@cornell.edu) who will route it to the Box team. Include the name of your app and what you wish to accomplish. Also include a screenshot of the Application Scope and Advanced features settings shown above (don’t include your clientID, clientSecret, or any private key information!). It will also be helpful if you describe how you plan to secure your app and its credentials (more on our approach below, if you wish to use that).

The turnaround time for approving our app was about 1 day. Once the Cornell Box team approves your through the Enterprise administrator, you can use your credentials and key to interact with the service.


Storing Credentials

The details of AWS SSM are beyond the scope of this article, but as mentioned earlier, our approach is to store the JSON blob (which contains the client secrets and private key) in an encrypted AWS SSM parameter. More on that here: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html

This approach ensures that our credentials are encrypted at rest, that any accesses of the credentials are logged, and that they exist in a single place for easy rotation. We grant access to the parameter and associated KMS key to our application via IAM policy associated with an ECS task role.

The example code includes a method for retrieving the parameter that may be useful if you choose to take this approach.


Using the Box API

Once your app is approved and you have your credential management approach in place, you’re all set to start interacting with the API. A full reference is available here: https://developer.box.com/v2.0/docs/getting-started-box-integration

This primer on using the JWT client specifically is also useful: https://github.com/box-community/jwt-app-primer


Our specific use case and example

As I mentioned, our use case was to publish generated files to specific users, so I’ll walk through that example below. Note — the example code is using a wrapper library that we created (available in the github repository) call cu_box.client

In order to allow our app to access an existing folder, we need to grant it access. To do that, we need to know its service id. The example app includes a file called “who_is_service_user.py” that can determine this for you (just replace the parameter name, or otherwise pipe in your credential JSON file):

from cu_box import client
credentials_json = client.get_aws_ssm_parameter('box_integration_credentials')
box = client.get_box_client(credentials_json)
service_account = box.user().get()
print 'Acting as user:'
print 'Service Account name: {0}'.format(service_account.name)
print 'Service Account login: {0}'.format(service_account.login)

The output of the Service Account login here will be in the form of an email address — this is a real Box user that can be granted access to folders like this:

In this example, I’m creating a new folder, and then inviting my app’s service user (AutomationUser_etc@boxdevedition.com) as a collaborator.

Once a folder is created, you’ll need to find the folder ID… it’s included in the folder URI in the UI:

Finally, we can post a file to box as shown in the “post_example_file.py” file:

from cu_box import client
EXAMPLE_FOLDER_ID = '40977453470'
EXAMPLE_FILE = './example_file.txt'
credentials_json = client.get_aws_ssm_parameter('box_integration_credentials')
box = client.get_box_client(credentials_json)
client.write_file_to_box(box, EXAMPLE_FILE, EXAMPLE_FOLDER_ID)

The write_file_to_box method supports versioning, so publishing the same file multiple times will increment the version in Box (and prior versions will be available per the Box retention policy).


That’s it

OK — that’s all there is to it. Feel free to reach out if you have questions!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.