REST interface

Authentication

Authentication is done through standard HTTP Authorization header containing a provider name and provider-specific credentials.

Generic format of the exchange authorization header is:

Authorization: exchange-PROVIDER CREDENTIALS

Provider noauth can be used to specify that no authentication is to be done and is equivalent to omitting the Authorization header.

Crypto authentication provider

crypto provider can be used to sign and verify HTTP messages using the stock/default crypto library provided by for example Cryptodome or any other DSA/RSA-compatible API.

To sign a message using this method, first a signable string is created from the HTTP request. This is the concatenation of the method, and values of Content-MD5, Content-Type and Date, Message-Id headers, separated by a newline (\n). The headers are sorted alphabetically, so the value of Content-Type appears before the value of Date. The Message-Id is mandatory and should be unique.

Given a sample request:

POST /file/ HTTP/1.1
Host: example.com
Content-Type: application/x-hdf5
Content-MD5: f919609e57df334754cdb410c7847058
Content-Length: nnn
Date: Tue, 10 Jan 2012 19:03:34 GMT
Message-Id: 9620924f-6198-470b-b3d1-6b26042fd7b9

<h5-file>

The created signable string would be:

POST
f919609e57df334754cdb410c7847058
application/x-hdf5
Tue, 10 Jan 2012 19:03:34 GMT
9620924f-6198-470b-b3d1-6b26042fd7b9

The format of of the authorization header is:

Authorization: exchange-keyczar KEYNAME:SIGNATURE

where KEYNAME is the name of the key the server will use to look up a key for verifying the signature and SIGNATURE is the base64-encoded signature that was created.

On unsuccesful authentication, a 401 Unauthorized response will be sent, with available authentication providers in WWW-Authenticate header, one provider per header:

WWW-Authenticate: exchange-crypto

Creating signatures

If you are using a different language than python and want to create messages then you will have to implement your own signature handling. The implementation in baltrad-exchange are using PyCryptodome and is straight forward without any extra meta-information in the data to be signed and should be quite easy to implement in a different language.

from Cryptodome.PublicKey import DSA, RSA
from Cryptodome.Signature import DSS, pkcs1_15
from Cryptodome.Hash import SHA256
import base64

key = DSA.importKey(open("mydsakey.private").read())
msg = "This is a message to sign"

hashed = SHA256.new(bytes(msg, "UTF-8"))
signer = DSS.new(key, 'fips-186-3')
signature = signer.sign(hashed)
result = base64.urlsafe_b64encode(signature).decode("ascii")

print("Signature: %s"%result)

When running the above code the signature will be printed and can look something like

Signature: CKQHaXw1FuLPjjNt8Y2zX3qCdxaTNfCEya1nQ6UhvrFewvYfmWEpc1NEms8FbhvdK4W0YH50S8k=

Keyczar authentication provider (Legacy)

keyczar provider can be used to sign and verify HTTP messages using Keyczar. Keyczar has been deprecated and is no longer supported. Since baltrad-dex and baltrad-db is still using it we have provided a simple implementation providing the necessary parts to continue communicating with these systems.

The behaviour when signing messages using Keyczar is similar to Crypto. First a signable string is created from the HTTP request. This is the concatenation of the method, query path and values of Content-MD5, Content-Type and Date headers, separated by a newline (\n). The headers are sorted alphabetically, so the value of Content-Type appears before the value of Date.

Given a sample request:

POST /source/ HTTP/1.1
Host: example.com
Content-Type: application/json
Content-MD5: f919609e57df334754cdb410c7847058
Content-Length: nnn
Date: Tue, 10 Jan 2012 19:03:34 GMT

{
  "source": {
    "name": "source_name",
    "values": {
        "key1": "value1",
        "key2": "value2",
    }
  }
}

The created signable string would be:

POST
/source/
f919609e57df334754cdb410c7847058
application/json
Tue, 10 Jan 2012 19:03:34 GMT

The format of of the authorization header is:

Authorization: exchange-crypto KEYNAME:SIGNATURE

where KEYNAME is the name of the key the server will use to look up a key for verifying the signature and SIGNATURE is the base64-encoded signature from keyczar.keyczar.Signer.Sign().

On unsuccesful authentication, a 401 Unauthorized response will be sent, with available authentication providers in WWW-Authenticate header, one provider per header:

WWW-Authenticate: exchange-keyczar

Operations

Post file

Request
Synopsis:

POST /file/

Headers:

Content-Length, Content-Type, Date, Message-Id

Body:

file content

POST /file/ HTTP/1.1
Host: example.com
Content-Length: nnn
Content-Type: application/x-hdf5
Date: 2022-11-11 10:00:00 UTC
Message-Id: 9620924f-6198-470b-b3d1-6b26042fd7b9

[nnn bytes of file data]
Response
Headers:

Content-Length, Content-Type, Location

Status:

200 OK - file has been handled

HTTP/1.1 200 OK