Enterprise Level Access Control with Keys and Entitlements

entitlements200x190

“Private repositories”, “Teams and Organizations”, “Permissions”…, sounds like that’s all you need to provide secure private downloads. Well, not quite. Those are great features that fit the bill if your consumer is a Bintray user. But what if she isn’t? Well, then there are signed URLs. Those should do the trick. Just sign your file and send your consumer the URL. But what if you want to share an entire repository, package or version with a group of people, but need to give each of them different privileges. Some can only view or download your files, but others should be able to delete your files or upload new ones. Signed URLs don’t cover that kind of control. They are great for single files, but for more fine-grained access control, you need a more sophisticated feature. That’s where entitlements and keys come in.

“Entitlements,” you said? What are those?

Entitlements are privileges you can give anyone…yes anyone, not only Bintray users, to entities in your private repositories. “Entities” means anything that can contain files – a whole repository, a path within the repository, a specific package or a specific version. “Privileges” means “rw”  – download, upload and delete, or “r” – download only. If you didn’t notice, the combination of entities and privileges gives you any level of granularity that you need for providing access.

But how do you unlock entitlements?

I guess you get the hint. Keys unlock entitlements. You generate a key along with its password (or Bintray can generate one for you automatically). Your user will have to provide the username and password to enable the key that unlocks the entitlement. That’s where the security lies. Only users who have both the username and the password of the key that you provide to them can access your repository entities according to the entitlements you created.

So how does it all work?

Two simple steps using Bintray’s REST API:

  1. Create keys. You can supply a password for each key you create, or Bintray can generate one for you.

  2. Create entitlements. When you create entitlements, you specify which keys to apply to them.

Now all you need to do is provide your user with the username and password for one of those keys. Your user now applies a REST API to access your private Bintray resource while including the key and password you provided as parameters to the API call. Bintray will check if there is an entitlement that allows access to that resource, and if that entitlement has the key that the user specified associated with it.

Let’s see an example at work

Let’s say user “ACMECorp” has a private repository called “acme”.

This private repo contains several versions of acprod under the “acmecorprod” directory that are protected from public access.

ACMECorp wants to authorize a “platinum customer” to download the different versions. Needless to say, “Ms. Platinum” does not have a Bintray account.

First, ACMECorp needs to create a key. Bintray offers two ways to maintain control over keys that are distributed to outside users. The easy way is to just put an expiry date on the key. A more advanced method is to set up an internal server that is used to validate and authenticate keys, and provide the server URL to Bintray when a key is created. Every time a user tries to access ACMECorp’s repositories, Bintray will validate the key using  the URL that ACMECorp provided when creating it. Since ACMECorp is very careful with its key, let’s assume they want to validate keys with their own systems:

curl -XPOST -uacmecorp:APIKEY “https://api.bintray.com/users/acmecorp/download_keys
{
“id”: “key1″,
“expiry”: 7956915742000
“existence_check”:{
      “url”: “http://callbacks.myci.org/username=:username,password=:password”,
      “cache_for_secs”: 60
      }
}

Bintray creates a key and its associated password

Status: 201 Created
{
"username": "key1@acmecorp",
"password": "8fdf84d2a814783f0fc2ce869b5e7f6ce9f286a0"
}

ACMECorp now creates an entitlement that provides download privileges to the acmecorprod directory, while assigning key1 that was just created

curl -XPOST -uacmecorp:APIKEY "https://api.bintray.com/packages/acmecorp/acme/acprod/entitlements
{
"access": "r",
"download_keys": ["key1"]
}

Bintray responds:

Status: 201 Created
{
"id": "7f8d57b16c1046e38062ea3db91838ff77758eca",
"access": "r",
"download_keys": ["key1"]
}

Basically, that’s it. ACMECorp can now just provide the username “key1@acmecorp” and its password to Ms. Platinum who can now use them to access the acmecorprod directory in ACMECorp’s repository.

For example, to download version 1.0 of acprod, Ms. Platinum would use:

curl -XGET “https://dl.bintray.com/acmecorp/acme/acmecorprod/1.0/acprod.exe” -ukey1@acmecorp -p”8fdf84d2a814783f0fc2ce869b5e7f6ce9f286a0”

But what happens now if ACMECorp and Ms. Platinum have a falling out. When that happens, ACMECorp can just delete the download key from their validation server and “Hey presto”, Ms. Platinum is now locked out of ACMECorp’s repositories.

Try doing that on Docker Hub, RubyGems.org, NuGet Gallery, Maven Central or any other repository or download center out there. Bintray is the only one that provides you with this level of control over access to your private resources.

Sign me up!

Bintray Premium gives you cool new features such as private repositories, permission management, more storage and so much more. One of the biggest benefits of using a Premium account is the ability to create expirable, signed URLs for your repositories’ content.

Signed URLs you said? What’s that?

A signed URL is an obscure URL with a (potentially) limited lifetime. When your artifacts are published in a private repository, each artifact is hidden from unauthorized Bintray users. If you want to allow any Bintray user, or even or a non-Bintray user to download your package, you can generate a one-time unique URL with an option to limit its validity so that is expires after a certain amount of time. You can also revoke any outstanding URLs at any time.

How does it work?

When you become a premium user in Bintray, your account holds unique, internal, private and public keys. The URL you decide to sign, will be encrypted and decrypted with those keys.

Let’s say user “srubin” has a private repository called “artifactory”.

This private repo contains a file, “artifactory.rar”, that protected from public access. Only authorized users can download it using the standard download link, which is:
https://dl.bintray.com/srubin/artifactory/com/jfrog/artifactorypro/artifactory.rar

Bintray Premium Link Signing

Bintray Premium Link Signing


To allow a one-off download of this file we will generate a signed URL for it using a simple REST call:

curl -XPOST -usrubin:APIKEY "https://api.bintray.com/signed_url/srubin/artifactory/com/jfrog/artifactorypro/artifactory.rar"

Response:

{
"url":"http://dl.bintray.com/srubin/artifactory/com/jfrog/artiafctorypro/artifactory.rar?expiry=1415101346415&signature=BfRaL2HDbCDsPyPThAnlI%2B0TG26NcH4i0ugyKZ%2FjevLiNfEdHXyUh0Q1NNGc1Pz7V1nZkeh9RAafrUyUE%2FMOFQ%3D%3D"
}

By default, this URL will be valid for 24 hours, but we can change that by specifying an expiry time in a simple JSON configuration document:

curl -XPOST -usrubin:APIKEY  -H "Content-Type: application/json"  -d "{\"expiry\":7956915742000}" https://api.bintray.com/signed_url/srubin/artifactory/com/jfrog/artiactorypro/artifactory.rar"

Response:

{
"url":"http://dl.bintray.com/srubin/artifactory/com/jfrog/artiactorypro/artifactory.rar?expiry=7956915742000&signature=g5OC3RXkFhnnFYfsgqFXw9J%2FfmwCzeIsd%2FHCRgm5VjCAhrzij1GPuAv0JwZPhGD0mEqs1y2WcQ77LMrDzp9%3D%3D"
}

More details about this API can be found in our documentation.

Summary

Signed, expirable URLs is a cool new feature of Bintray. It allows you to automate the generation of one-off download URLs and distribute them to any end user.

We will soon extend this feature to make it even cooler. Keep following to see what we have in store for you!

Hot on Bintray: Package Merging

We have recently introduced package merging: several packages from the same repository can now be merged into one. This is extremely useful when you have existing packages that are not aligned properly. For example, when you have many small technical packages (modules) that are logically one, single package, often using the same version scheme. Such situations are extremely common with maven packages that were created to reflect existing group IDs and that are effectively part of a single package (a common situation for packages imported to JCenter).

This is how it works:

Package Merging

(1) From the package you wish to merge the other packages into, click the new Merge button.
(BTW, have you noticed our new tabs UI? ;-))

(2) Once clicked, select the other packages to merge into the package you have just selected.
The merge page contains two sections: On the left side, a list for filtering, finding and selecting candidate packages in the same repo for merging.  On the right side, the  package that is the merge target – all other selected packages will be merged into it. Note that the default is the name of the package you have selected in step #1, but you can change this name.

How to Merge Packages?

(3) Click Merge to have the files and versions of all the selected packages merged. Note that your files will be laid-out in the repository exactly as they were before the merge – but you can now manage them and all your versions under a new, consolidated logical package.

Knock yourself out! 🙂