(copied from the Scientific Computing internal documentation as of 2019.Jul.29)
Idea
Request a read-only macaroon for a specific ntuple and use it to stream-read in ROOT
curl parameters
For the following examples we use curl, where the following options are handy
-L / --location
: let curl follow redirects, which is needed when we talk to a WebDAV door as entrypoint and the door wants to redirect our request to the dCache pool for the actual file location--fail, --include
: in case of an error,--fail
will just print a one-line message instead of dumping the full server http-error page; on the other hand--include
will we more verbose and dump also the full header--capath
: path where the CA root certificates for the host certs are--cacert, --cert, --key
: path to the certificate&key for authz - in the grid world these are your grid user proxy
when using another tool/library, you probably need to check for the equivalent options
Depending on the tool/library, exporting the CA path might be picked up with something like
export X509_CERT_DIR=/cvmfs/grid.cern.ch/etc/grid-security/certificates
Basic macaroon handling
> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -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/" } }
> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read HTTP/1.1 200 OK Date: Mon, 29 Jul 2019 10:23:02 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: 1534 { "macaroon": "MDAzNWxvY2F0aW9u...", "uri": { "targetWithMacaroon": "https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read?authz=MDAzNWxvY2F0aW9uIE9wdG....", "baseWithMacaroon": "https://dcache-se-doma.desy.de:2880/?authz=MDAzNWxvY2F0aW9uIE9wdGlv....", "target": "https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read", "base": "https://dcache-se-doma.desy.de:2880/" } }
see the ISO 8601 documentation for the date/period formatting.
The same using Python requests library:
This comes from dcache event demo and is hardwired against dcache-xdc.desy.de. It uses basic auth, but could use x509 or a management macaroon as well.
download macaroondef get_download_link(self, path, time = "PT1H"): if path.startswith("https://dcache-xdc.desy.de/"): path = path[len("https://dcache-xdc.desy.de/"):] api = "https://{}:{}@dcache-xdc.desy.de/".format(self.dcache_user, self.dcache_password) headers = {"Content-Type": "application/macaroon-request"} data = {"caveats": ["activity:DOWNLOAD", "path:" + path], "validity":time} res = post(api, headers = headers, data = json.dumps(data)) macaroon = json.loads(res.content.decode("ascii"))["macaroon"] return "https://dcache-xdc.desy.de/{}?authz={}".format(path,macaroon)
Listing & Reading
first, we try to read it with our proxy and pipe the result through xmllint for a more readable structure
> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read | xmllint --format -
Now we try without the macaroon and without the proxy
> curl [--include,--fail] -L --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read
the result should be empty.
Finally we try to list the directory and read the file it without the proxy but with our macaroon
>
> curl [--include,--fail] -L --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" -H "Authorization: Bearer MDAzNWxvY2F0a...." https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/read_txt.rnd | xmllint --format -
> MACAROON=MDAzNWxvY2F0a.... # exporting the macaroon into an environment variable to make life easier
> curl [--include,--fail] -L --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X GET -H "Authorization: Bearer $MACAROON" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/read_txt.rnd --location --output /tmp/foo.foo
note, that we had to give the two header fields for the listing depth and the macaroon separately and could not combine them in one header field
Changing root dir
with the 'root
' caveat, the base path can be limited to a subtree
> curl [--include,--fail] -L --key /tmp/x509up_u26551 --cert /tmp/x509up_u26551 --cacert /tmp/x509up_u26551 --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST","root:/desy/Hamburg/MacaroonIO/"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/
> curl [--include,--fail] -L--capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X PROPFIND -H "Depth: 1" -H "Authorization: Bearer $MACAROON" https://dcache-se-doma.desy.de:2880/ | xmllint --format -
where dCache will return under nominally '/'
now only the content under /desy/Hamburg/MacaroonIO/
Limiting the path
Similarly the 'path
' limits a Macaroon just to one specific path, i.e., only the given file/path will be available with
> curl [--include,--fail] -L --key /tmp/x509up_u26551 --cert /tmp/x509up_u26551 --cacert /tmp/x509up_u26551 --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST","path:/desy/Hamburg/MacaroonIO/read/read_txt.rnd"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880
or
> curl [--include,--fail] -L --key /tmp/x509up_u26551 --cert /tmp/x509up_u26551 --cacert /tmp/x509up_u26551 --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:DOWNLOAD,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/read_txt.rnd
note, that a path limitation should betetr only be given once, i.e., in the URL (as short-cut) or in the header caveat field, since both are interpreted as caveats. When giving both, as full path URL and path caveat, both are applied and you would end up with to caveat, that might compete and break the Macaroon for you.
IP
Limit the IP range to the DESY subnet with the IP caveat
"caveats": ["ip:2001:638:700::/48","ip:131.169.0.0/16"]
Writing
for writing, request an upload macaroon, with which we can put a file under the path
> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:UPLOAD"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write
> curl --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -T /tmp/BXMuMu.root -H "Authorization: Bearer ${MACAROON}" https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write/
Mkdir
Similarly, a new directory can be created with the MANAGE activity
> curl [--include,--fail] -L --key $X509_USER_PROXY --cert $X509_USER_PROXY --cacert $X509_USER_PROXY --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X POST -H 'Content-Type: application/macaroon-request' -d '{"caveats": ["activity:MANAGE,LIST"],"validity": "P1DT12H"}' https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write
> curl --capath /cvmfs/grid.cern.ch/etc/grid-security/certificates/ -X MKCOL https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/write/new.d -H "Authorization: Bearer ${MACAROON}"
Deletion
A macaroon with a DELETION
activity can delete a path with -X DELETE
.
ROOT Example
Simple root example for Macaroon I/O (at least input via macaroons as I have not managed to let ROOT write to a remote URL in a specific format over http...)
export X509_CERT_DIR=/cvmfs/grid.cern.ch/etc/grid-security/certificates
export INMACAROON="https://dcache-se-doma.desy.de:2880/desy/Hamburg/MacaroonIO/read/BXMuMu.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); c1->cd(); TObject * inTree = inFile->Get("DecayTree"); inTree->Draw("Bplus_MM>>h1"); c1->SaveAs(OUTMACAROON); }
Links
- dCache Documentation
- dCache Talk by Paul
- macaroons.io
- http://macaroons.io/ for documentation and sandbox environment for macaroons
- https://eosc-pan-git.desy.de/pan/dcache-event-demo demo notebooks for event-driven computing with dCache.
- https://github.com/paulmillar/dynamic-processing Kafka Stream Processor to produce substreams from dCache billing stream
- https://github.com/SchuhMichael/dCache-FaaS-Tutorial/tree/master/kafka-stream Light Weight Stream Processor as part of our first interactive demo for event-driven programming with dCache (from dCache Workshop Mai 2018)