Edit me on GitHub

Macaroon Usage Examples

For the general introduction, see Macaroons

Hands-on examples on Macaroons with dCache

Macaroons can be generated and used on a HTTP level. In principle, most HTTP clients like curl or HTTP libraries should be usable to generate and use macaroons, when header information can be managed.

Good to Know

Environment Variables

Grid CA Certificates

Since the Grid infrasturcture uses separate certificate chains than the web, you have to explicitly point your tools to the Grid CA certificates. E.g., for curl use --capath ${CAPATH} where $CAPATH might point to

export CAPATH="/cvmfs/grid.cern.ch/etc/grid-security/certificates"

User Proxy/Certificate Envvars

A user needs to authenticate against a dCache instance to request an authorization macaroon. In the following, we will use a Grid user proxy for authz. Generate a valid user proxy for a mapped user, who is authorized to read/write paths on your instance.

For easier handling, we ensure that the user proxy is set in a ${X509_USER_PROXY} environment variable

export X509_USER_PROXY="/tmp/x509up_u##UID##"`

Necessary flags in curl to use the Grid user proxy for authentication are

curl --key ${X509_USER_PROXY} --cert ${X509_USER_PROXY} --cacert ${X509_USER_PROXY} ...

curl vs. HTTP redirects

curl does not follows HTTP redirects like 301 or 302. Use curl with flags --location/-L, else a curl HTTP request going to a door for a file might not follow the door’s redirect to the actual pool.

Macaroon Requests

Example Macaroon Request

Basic request to request a full-power Macaroon with a valid Grid proxy

> curl [--include,--fail] --location --key ${X509_USER_PROXY}  --cert ${X509_USER_PROXY}  --cacert ${X509_USER_PROXY}  --capath ${CAPTAH} -X POST -H 'Content-Type: application/macaroon-request' https://dcache-se-doma.desy.de:2880
HTTP/1.1 200 OK
Date: Mon, 29 Jul 2019 10:04:38 GMT
Server: dCache/5.2.1
Content-Type: application/json
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PROPFIND
Access-Control-Allow-Headers: Content-Type, Authorization
Content-Length: 1082
"macaroon": "MDAxY2xvY2F0...",
"uri": {
"targetWithMacaroon": "https://dcache-se-doma.desy.de:2880/?authz=MDAxY2xvY2F0aW9uIE9wd....",
"baseWithMacaroon": "https://dcache-se-doma.desy.de:2880/?authz=MDAxY2xvY2F0....",
"target": "https://dcache-se-doma.desy.de:2880/",
"base": "https://dcache-se-doma.desy.de:2880/"

For easier handling in the following, export the macaroon in an environment variable

export MACAROON="MDAxY2xvY2F0aW9uIE9wd..."

Macaoon limited in time and on the path

Generate a macaroon limited to list and download from a specific directory and is valid for 1 day and 12 hours. The caveats have top be put into the request’s header. For curl

> curl [--include,--fail] -L --key $X509_USER_PROXY  --cert ${X509_USER_PROXY}  --cacert ${X509_USER_PROXY}  --capath ${CAPATH}  -X POST  -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/path/allowed/to/access

See the ISO 8061 documentaion on the syntax for durations .

At maximum, a macaroon can be valid for one week.

Listing & Reading

Listing a Directory

Listing a directory content via the PROFIND WebDAV extension to HTTP. Put the previously requested macaroon into the request’s header. Here, we pipe the resulting info page from dCache with the directory content to xmllint for better readability on the command line

> curl [--include,--fail] -L --capath ${CAPATH} -X PROPFIND -H "Depth: 1" -H "Authorization: Bearer ${MACAROON}" https://dcache-se-doma.desy.de:2880/path/allowed/to/access | xmllint --format -

Note, that we had to give two header fields separately, one for the listing depth and one containing the macaroon.

Downloading a File

Get a file with HTTP GET

 curl [--include,--fail] -L --capath ${CAPATH} -X GET -H "Authorization: Bearer ${MACAROON}" https://dcache-se-doma.desy.de:2880/path/allowed/to/access/file.foo --output /tmp/output.foo

Changing the root Directory

With the ‘root’ caveat, the base path can be limited to a subtree of the namespace. I.e., You can generate a macaroon allowing access to files living under /path/allowed/to/access/ - and limit the visible namespace to the macaroon bearer to the same subdirectory

Request a macaroon allowing for listing and downloading files under /path/allowed/to/access/ with a lifetime of 1.5 days and the root direcory constraint to the same subdirectory

> curl [--include,--fail] -L --key $X509_USER_PROXY  --cert ${X509_USER_PROXY}  --cacert ${X509_USER_PROXY} --capath ${CAPATH}  -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST","root:/path/allowed/to/access/"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/path/allowed/to/access/

For the bearer of the resulting macaroon, listing of the root directory content will then be put into the afromentioned path of the namespace

> curl [--include,--fail] -L--capath ${CAPATH} -X PROPFIND -H "Depth: 1" -H "Authorization: Bearer ${MACAROON}" https://dcache-se-doma.desy.de:2880/

Limiting the path

Similarly, one can generate a macaroon limiting the bearer’s path to a specific path, i.e., only the given file/path will be available to the macaroon bearer.

> curl [--include,--fail] -L  --key $X509_USER_PROXY  --cert ${X509_USER_PROXY}  --cacert ${X509_USER_PROXY} --capath ${CAPATH} -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST","path:/path/allowed/to/access/file.foo"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880


> curl [--include,--fail] -L  --key $X509_USER_PROXY  --cert ${X509_USER_PROXY}  --cacert ${X509_USER_PROXY} --capath ${CAPATH} -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/path/allowed/to/access/file.foo

More Caveats

IP Range

To limit for example the IP range to the DESY subnet, add a caveat to the header

curl ... -d '{"caveats": ["ip:2001:638:700::/48","ip:"],"validity":...} ...

Limiting Writing/Upload

For a write-only dropbox macaroon, that would allow the bearer to write only onto https://dcache-se-doma.desy.de:2880/path/allowed/to/access/file.foo

curl ...  -d '{"caveats": ["activity:UPLOAD"],"validity":...}' https://dcache-se-doma.desy.de:2880/path/allowed/to/access/file.foo

(to allow the macaroon bearer to also list and read the path, do not forget the DOWNLOAD & LIST caveats)

File Upload/HTTP PUT

To write onto the path as the macaroon bearer

curl --location --capath ${CAPATH}  -T /path/to/file/to/be/uploaded https://dcache-se-dome.desy.de:2880/path/allowed/to/access/file.foo?authz=${MACAROON}

Optionally, one could use also the root caveat and constraint the root pathfor the bearer, so that one would not need to know the full path and probably just write to the remapped /

Directory Creation

Create a macaroon, that allows the bearer to create subdirectories

curl ... -d '{"caveats": ["activity:MANAGE,LIST"],"validity": ...}' https://dcache-se-dome.desy.de:2880/path/allowed/to/access/

and as bearer create a new sub-directory with the MKCOL method in WebDAV

curl --capath ${CAPATH} -X MKCOL https://dcache-se-doma.desy.de:2880/path/allowed/to/access/mynew.d -H "Authorization: Bearer ${MACAROON}"


To allow a macaroon bearer the deletion of files etc., apply the DELETE caveat during creation

{"caveats": ["activity:DELETE"],"validity": ...}

The corresponding method/curl request is -X DELETE - use with care.

Macaroon I/O in ROOT

Since the HTTP libraries used by ROOT support all the I/O methods for streaming read/writes over HTTP, macaroons can in principle be used directly. For example, to read a ntuple root file from HTTP authorized with a macaroon and write a plot locally

export CAPATH=...
export INMACAROON="https://dcache-se-doma.desy.de:2880/https://dcache-se-doma.desy.de:2880/path/allowed/to/access/myfootuple.root?authz=MDA0MWxvY..."
export OUTMACAROON="/tmp/macaroonio_out.png"
#include "TH1.h"
#include "TList.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TSystem.h"
void macaroonio() {
  const char * INMACAROON = gSystem->Getenv("INMACAROON");
  const char * OUTMACAROON = gSystem->Getenv("OUTMACAROON");
  TFile *inFile = TFile::Open(INMACAROON);
  TH1D *h1 = new TH1D("h1","Hello Macaroon",200,5000,7000);
  TCanvas * c1 = new TCanvas("c1", "c1", 900, 600);
  TObject * inTree = inFile->Get("DecayTree");