An average size of an Escher implementation should be no more than 500-1000 lines of code, depending on how granular are the methods you create. Every modern programming language has the supporting libraries (like HMAC calculation) you will need, your job is to go through the specification step-by-step and implement the methods.
We have tried our best to divide the tasks and create blocks you can implement within some hours. This way you will be able to estimate the time you need for a full implementation, and you also will have the status of your code.
Also, there are language independent test cases you can run against your code. We don’t recommend starting with the tests. According to our experience, that’s the harder way. At the end, you should add the tests, which will help a lot finalizing your implementation.
This guide has to be finished, but already can give you some ideas. We are going to add more details. You can always check one of the implementations to get more ideas about how it works. At the moment, the EscherRuby implementation is in the best shape.
1. Implement a Generic EscherRequest Class¶
For a programming language, typically there’s no general request representation. Some languages have a commonly used request object, but for other languages, every framework might have its own representation. It is also typical that the request object a client creates is different from the request object a controller on the server side receives.
It’s a good practice creating an EscherRequest class you can instantiate with different types of request objects. It can provide an interface that Escher can use easily.
The Request class should be instantiated with request objects, and provide the following interface for the Escher implementation:
- get the HTTP method (a string)
- get the Headers (should be an array of key-value pairs)
- get the Host (a string)
- get the Path (a string starting with /, not including the question mark, query parameters)
- get the Query parameters (should be an array of key-value pairs)
- get the Body (a string)
- set a Header
- has a Header?
- give back the request (with possible modifications via header settings, but as the original object’s class)
2. Create an Escher Class¶
Create an Escher class you can instantiate with the following parameters and their defaults. Only the credential scope is required, the others are optional:
- credential_scope - no default
- algo_prefix = ‘ESR’
- vendor_key = ‘Escher’
- hash_algo = ‘SHA256’
- current_time = Time.now
- auth_header_name = ‘X-Escher-Auth’
- date_header_name = ‘X-Escher-Date’
- clock_skew = 900
3. Canonicalize a Request¶
Create a method that can take a request object, and create a canonicalized request, using the Escher instances’ parameters. Don’t care about the details yet, but handle the basic cases only. There will be a step later about implementing all the details of the specification. The output should be something like at 2.1.7. Concatenating the Canonicalized Parts.
4. Create a Signing String¶
Build a signing string from the canonicalized request and the parameters of the Escher instance object. Example output is available at 2.2.5. Concatenating the Signing String. It should be very straightforward to build the signing string.
5. Create a Signing Key¶
Implement the signing key creation algorithm described at 2.2.6. The Signing Key. It should be a short code. Note that the output will be a binary value.
6. Create the Signature¶
Create a signature from the signing string and the signing key.
7. Add the Signature to the Headers¶
Call the EscherRequest’s header settings, and set a proper Auth header, according to 2.3. Adding the Signature to the Request.
8. Canonicalize the Path Properly¶
Now go back to your path canonicalization, and fine tune it according to the specification. Most of the time, ready-to-use libraries will be available for you, but sometimes they are not fully compatible with the standards or the Escher specification.
9. Canonicalize the Query Parameters Properly¶
And fine tune the query parameter canonicalization as well. If EscherRequest provides the query parameters as an array, then
10. Canonicalize the Headers Properly¶