mirror of
https://github.com/almet/notmyidea.git
synced 2025-04-28 19:42:37 +02:00
- Added the ability to display book cover for the category "Lectures" if ISBN cover is available. - Moved author's name into a small tag for better hierarchy and readability. - Implemented a feature to indicate link sizes depending on the number of articles associated with a given tag. - Implemented a mini footer element displaying an RSS feed icon. - Improved category display using description dictionary. - Added a new plugin "isbn_downloader" to fetch ISBN information when needed. - Included the count of articles for each category. - Implemented changes for better layout and readability of tags and categories. - Adjusted the layout of the webpage, improving the overall look of the page. - Included "requests" in the requirements.txt for supplanting dependencies required by the new plugin and/or features.
223 lines
7.1 KiB
Markdown
223 lines
7.1 KiB
Markdown
# What's Hawk and how to use it?
|
|
|
|
At Mozilla, we recently had to implement [the Hawk authentication
|
|
scheme](https://github.com/hueniverse/hawk) for a number of projects,
|
|
and we came up creating two libraries to ease integration into pyramid
|
|
and node.js apps.
|
|
|
|
But maybe you don't know Hawk.
|
|
|
|
Hawk is a relatively new technology, crafted by one of the original
|
|
[OAuth](https://en.wikipedia.org/wiki/OAuth) specification authors, that
|
|
intends to replace the 2-legged OAuth authentication scheme using a
|
|
simpler approach.
|
|
|
|
It is an authentication scheme for HTTP, built around [HMAC
|
|
digests](https://en.wikipedia.org/wiki/Hmac) of requests and responses.
|
|
|
|
Every authenticated client request has an Authorization header
|
|
containing a MAC (Message Authentication Code) and some additional
|
|
metadata, then each server response to authenticated requests contains a
|
|
Server-Authorization header that authenticates the response, so the
|
|
client is sure it comes from the right server.
|
|
|
|
## Exchange of the hawk id and hawk key
|
|
|
|
To sign the requests, a client needs to retrieve a token id and a token
|
|
key from the server.
|
|
|
|
Hawk itself does not define how these credentials should be exchanged
|
|
between the server and the client. The excellent team behind [Firefox
|
|
Accounts](http://accounts.firefox.com) put together a scheme to do that,
|
|
which acts like the following:
|
|
|
|
<div class="note">
|
|
|
|
<div class="admonition-title">
|
|
|
|
Note
|
|
|
|
</div>
|
|
|
|
All this derivation crazyness might seem a bit complicated, but don't
|
|
worry, we put together some libraries that takes care of that for you
|
|
automatically.
|
|
|
|
If you are not interested into these details, you can directly jump to
|
|
the next section to see how to use the libraries.
|
|
|
|
</div>
|
|
|
|
When your server application needs to send you the credentials, it will
|
|
return it inside a specific Hawk-Session-Token header. This token can be
|
|
derived to split this string in two values (hawk id and hawk key) that
|
|
you will use to sign your next requests.
|
|
|
|
In order to get the hawk credentials, you'll need to:
|
|
|
|
First, do an [HKDF derivation](http://en.wikipedia.org/wiki/HKDF) on the
|
|
given session token. You'll need to use the following
|
|
parameters:
|
|
|
|
key_material = HKDF(hawk_session, "", 'identity.mozilla.com/picl/v1/sessionToken', 32*2)
|
|
|
|
<div class="note">
|
|
|
|
<div class="admonition-title">
|
|
|
|
Note
|
|
|
|
</div>
|
|
|
|
The `identity.mozilla.com/picl/v1/sessionToken` is a reference to this
|
|
way of deriving the credentials, not an actual URL.
|
|
|
|
</div>
|
|
|
|
Then, the key material you'll get out of the HKDF need to be separated
|
|
into two parts, the first 32 hex caracters are the hawk id, and the next
|
|
32 ones are the hawk key.
|
|
|
|
Credentials:
|
|
|
|
```
|
|
javascript
|
|
credentials = {
|
|
'id': keyMaterial[0:32],
|
|
'key': keyMaterial[32:64],
|
|
'algorithm': 'sha256'
|
|
}
|
|
```
|
|
|
|
## Httpie
|
|
|
|
To showcase APIs in the documentation, I like to use
|
|
[httpie](https://github.com/jakubroztocil/httpie), a curl-replacement
|
|
with a nicer API, built around [the python requests
|
|
library](http://python-requests.org).
|
|
|
|
Luckily, HTTPie allows you to plug different authentication schemes for
|
|
it, so [I wrote a
|
|
wrapper](https://github.com/mozilla-services/requests-hawk) around
|
|
[mohawk](https://github.com/kumar303/mohawk) to add hawk support to the
|
|
requests lib.
|
|
|
|
Doing hawk requests in your terminal is now as simple as:
|
|
|
|
$ pip install requests-hawk httpie
|
|
$ http GET localhost:5000/registration --auth-type=hawk --auth='id:key'
|
|
|
|
In addition, it will help you to craft requests using the requests
|
|
library:
|
|
|
|
```python
|
|
|
|
import requests
|
|
from requests_hawk import HawkAuth
|
|
|
|
hawk_auth = HawkAuth(
|
|
credentials={'id': id, 'key': key, 'algorithm': 'sha256'})
|
|
|
|
requests.post("/url", auth=hawk_auth)
|
|
```
|
|
|
|
Alternatively, if you don't have the token id and key, you can pass the
|
|
hawk session token I talked about earlier and the lib will take care of
|
|
the derivation for you:
|
|
|
|
```python
|
|
|
|
hawk_auth = HawkAuth(
|
|
hawk_session=resp.headers['hawk-session-token'],
|
|
server_url=self.server_url
|
|
)
|
|
requests.post("/url", auth=hawk_auth)
|
|
```
|
|
|
|
## Integrate with python pyramid apps
|
|
|
|
If you're writing pyramid applications, you'll be happy to learn that
|
|
[Ryan Kelly](https://www.rfk.id.au/blog/) put together a library that
|
|
makes Hawk work as an Authentication provider for them. I'm chocked how
|
|
simple it is to use it.
|
|
|
|
Here is a demo of how we implemented it for Daybed:
|
|
|
|
```python
|
|
|
|
from pyramid_hawkauth import HawkAuthenticationPolicy
|
|
|
|
policy = HawkAuthenticationPolicy(decode_hawk_id=get_hawk_id)
|
|
config.set_authentication_policy(authn_policy)
|
|
```
|
|
|
|
The get\_hawk\_id function is a function that takes a request and a
|
|
tokenid and returns a tuple of (token\_id, token\_key).
|
|
|
|
How you want to store the tokens and retrieve them is up to you. The
|
|
default implementation (e.g. if you don't pass a decode\_hawk\_id
|
|
function) decodes the key from the token itself, using a master secret
|
|
on the server (so you don't need to store anything).
|
|
|
|
## Integrate with node.js Express apps
|
|
|
|
We had to implement Hawk authentication for two node.js projects and
|
|
finally came up factorizing everything in a library for express, named
|
|
[express-hawkauth](https://github.com/mozilla-services/express-hawkauth).
|
|
|
|
In order to plug it in your application, you'll need to use it as a
|
|
middleware:
|
|
|
|
```
|
|
javascript
|
|
var express = require("express");
|
|
var hawk = require("express-hawkauth");
|
|
app = express();
|
|
|
|
var hawkMiddleware = hawk.getMiddleware({
|
|
hawkOptions: {},
|
|
getSession: function(tokenId, cb) {
|
|
// A function which pass to the cb the key and algorithm for the
|
|
// given token id. First argument of the callback is a potential
|
|
// error.
|
|
cb(null, {key: "key", algorithm: "sha256"});
|
|
},
|
|
createSession: function(id, key, cb) {
|
|
// A function which stores a session for the given id and key.
|
|
// Argument returned is a potential error.
|
|
cb(null);
|
|
},
|
|
setUser: function(req, res, tokenId, cb) {
|
|
// A function that uses req and res, the hawkId when they're known so
|
|
// that it can tweak it. For instance, you can store the tokenId as the
|
|
// user.
|
|
req.user = tokenId;
|
|
}
|
|
});
|
|
|
|
app.get("/hawk-enabled-endpoint", hawkMiddleware);
|
|
```
|
|
|
|
If you pass the createSession parameter, all non-authenticated requests
|
|
will create a new hawk session and return it with the response, in the
|
|
Hawk-Session-Token header.
|
|
|
|
If you want to only check a valid hawk session exists (without creating
|
|
a new one), just create a middleware which doesn't have any
|
|
createSession parameter defined.
|
|
|
|
## Some reference implementations
|
|
|
|
As a reference, here is how we're using the libraries I'm talking about,
|
|
in case that helps you to integrate with your projects.
|
|
|
|
- The Mozilla Loop server [uses hawk as authentication once you're
|
|
logged in with a valid BrowserID
|
|
assertion](https://github.com/mozilla-services/loop-server/blob/master/loop/index.js#L70-L133);
|
|
request, to keep a session between client and server;
|
|
- [I recently added hawk support on the Daybed
|
|
project](https://github.com/spiral-project/daybed/commit/f178b4e43015fa077430798dcd3d0886c7611caf)
|
|
(that's a pyramid / cornice) app.
|
|
- It's also interesting to note that Kumar put together [hawkrest, for
|
|
the django rest
|
|
framework](http://hawkrest.readthedocs.org/en/latest/)
|