Skip to content
This repository was archived by the owner on Apr 13, 2024. It is now read-only.

Commit e65f5f3

Browse files
committed
Updated for Draft 3.
1 parent 19c94dc commit e65f5f3

File tree

7 files changed

+35
-17
lines changed

7 files changed

+35
-17
lines changed

CHANGELOG.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
11
httpsig Changes
22
---------------
33

4+
1.1.0 (2014-Jul-24)
5+
-------------------
6+
7+
* Changed "(request-line)" to "(request-target)" to comply with Draft 3.
8+
9+
1.0.3 (2014-Jul-09)
10+
-------------------
11+
12+
* Unified the default signing algo under one setting. Setting httpsig.sign.DEFAULT_SIGN_ALGORITHM changes it for all future instances.
13+
* Handle invalid params a little better.
14+
15+
1.0.2 (2014-Jul-02)
16+
-------------------
17+
18+
* Ensure we treat headers as ASCII strings.
19+
* Handle a case in the authorization header where there's garbage (non-keypairs) after the method name.
20+
421
1.0.1 (2014-Jul-02)
522
~~~~~~~~~~~~~~~~~~~
623

README.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ httpsig
77
.. image:: https://travis-ci.org/ahknight/httpsig.svg?branch=develop
88
:target: https://travis-ci.org/ahknight/httpsig
99

10-
Sign HTTP requests with secure signatures according to the current IETF HTTP Signatures draft_ specification. This is a fork of the original module_ to fully support both RSA and HMAC schemes as well as unit test both schemes to prove they work. It's being used in production and is actively-developed.
10+
Sign HTTP requests with secure signatures according to the IETF HTTP Signatures specification (`Draft 3`_). This is a fork of the original module_ to fully support both RSA and HMAC schemes as well as unit test both schemes to prove they work. It's being used in production and is actively-developed.
1111

12-
See the original project_, original Python module_, original spec_, and current IETF draft_ for more details on the signing scheme.
12+
See the original project_, original Python module_, original spec_, and `current IETF draft`_ for more details on the signing scheme.
1313

1414
.. _project: https://github.com/joyent/node-http-signature
1515
.. _module: https://github.com/zzsnzmn/py-http-signature
1616
.. _spec: https://github.com/joyent/node-http-signature/blob/master/http_signing.md
17-
.. _draft: https://datatracker.ietf.org/doc/draft-cavage-http-signatures/
17+
.. _`current IETF draft`: https://datatracker.ietf.org/doc/draft-cavage-http-signatures/
18+
.. _`Draft 3`: http://tools.ietf.org/html/draft-cavage-http-signatures-03
1819

1920
Requirements
2021
------------
@@ -54,7 +55,7 @@ For general use with web frameworks:
5455
key_id = "Some Key ID"
5556
secret = b'some big secret'
5657
57-
hs = httpsig.HeaderSigner(key_id, secret, algorithm="hmac-sha256", headers=['(request-line)', 'host', 'date'])
58+
hs = httpsig.HeaderSigner(key_id, secret, algorithm="hmac-sha256", headers=['(request-target)', 'host', 'date'])
5859
signed_headers_dict = hs.sign({"Date": "Tue, 01 Jan 2014 01:01:01 GMT", "Host": "example.com"}, method="GET", path="/api/1/object/1")
5960
6061
For use with requests:

httpsig/sign.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ def sign(self, headers, host=None, method=None, path=None):
9292
9393
headers is a case-insensitive dict of mutable headers.
9494
host is a override for the 'host' header (defaults to value in headers).
95-
method is the HTTP method (required when using '(request-line)').
96-
path is the HTTP path (required when using '(request-line)').
95+
method is the HTTP method (required when using '(request-target)').
96+
path is the HTTP path (required when using '(request-target)').
9797
"""
9898
headers = CaseInsensitiveDict(headers)
9999
required_headers = self.headers or ['date']

httpsig/tests/test_signature.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_default(self):
3939

4040
def test_all(self):
4141
hs = sign.HeaderSigner(key_id='Test', secret=self.key, headers=[
42-
'(request-line)',
42+
'(request-target)',
4343
'host',
4444
'date',
4545
'content-type',
@@ -65,5 +65,5 @@ def test_all(self):
6565
self.assertIn('signature', params)
6666
self.assertEqual(params['keyId'], 'Test')
6767
self.assertEqual(params['algorithm'], 'rsa-sha256')
68-
self.assertEqual(params['headers'], '(request-line) host date content-type content-md5 content-length')
69-
self.assertEqual(params['signature'], 'vYJio4AxbN38TKdzE1Qk/3qXhzTaBS7zUIPCqV+NsjLSf8ZK/19L9ErTz8FYBAW8Gko2dEaU70McrIO33k0PUlPsWvbGn/IhnU14rvSPF/F+AnFVFeA9ivvvyVZQYYYp17fnNfiCzHrvUn+VnqMhRKA15Nr8KKwt9Eqi36wQ8Vg=')
68+
self.assertEqual(params['headers'], '(request-target) host date content-type content-md5 content-length')
69+
self.assertEqual(params['signature'], 'G8/Uh6BBDaqldRi3VfFfklHSFoq8CMt5NUZiepq0q66e+fS3Up3BmXn0NbUnr3L1WgAAZGplifRAJqp2LgeZ5gXNk6UX9zV3hw5BERLWscWXlwX/dvHQES27lGRCvyFv3djHP6Plfd5mhPWRkmjnvqeOOSS0lZJYFYHJz994s6w=')

httpsig/tests/test_verify.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def test_signed_headers(self):
6060
METHOD = "POST"
6161
PATH = '/foo?param=value&pet=dog'
6262
hs = HeaderSigner(key_id="Test", secret=self.sign_secret, algorithm=self.algorithm, headers=[
63-
'(request-line)',
63+
'(request-target)',
6464
'host',
6565
'date',
6666
'content-type',
@@ -87,7 +87,7 @@ def test_incorrect_headers(self):
8787
key_id="Test",
8888
algorithm=self.algorithm,
8989
headers=[
90-
'(request-line)',
90+
'(request-target)',
9191
'host',
9292
'date',
9393
'content-type',
@@ -111,7 +111,7 @@ def test_extra_auth_headers(self):
111111
METHOD = "POST"
112112
PATH = '/foo?param=value&pet=dog'
113113
hs = HeaderSigner(key_id="Test", secret=self.sign_secret, algorithm=self.algorithm, headers=[
114-
'(request-line)',
114+
'(request-target)',
115115
'host',
116116
'date',
117117
'content-type',
@@ -126,7 +126,7 @@ def test_extra_auth_headers(self):
126126
'Content-Length': '18',
127127
}
128128
signed = hs.sign(unsigned, method=METHOD, path=PATH)
129-
hv = HeaderVerifier(headers=signed, secret=self.verify_secret, method=METHOD, path=PATH, required_headers=['date', '(request-line)'])
129+
hv = HeaderVerifier(headers=signed, secret=self.verify_secret, method=METHOD, path=PATH, required_headers=['date', '(request-target)'])
130130
self.assertTrue(hv.verify())
131131

132132

httpsig/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ def generate_message(required_headers, headers, host=None, method=None, path=Non
3232
signable_list = []
3333
for h in required_headers:
3434
h = h.lower()
35-
if h == '(request-line)':
35+
if h == '(request-target)':
3636
if not method or not path:
37-
raise Exception('method and path arguments required when using "(request-line)"')
37+
raise Exception('method and path arguments required when using "(request-target)"')
3838
signable_list.append('%s: %s %s' % (h, method.lower(), path))
3939

4040
elif h == 'host':

httpsig/verify.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ def __init__(self, headers, secret, required_headers=None, method=None, path=Non
5353
:param headers: A dictionary of headers from the HTTP request.
5454
:param secret: The HMAC secret or RSA *public* key.
5555
:param required_headers: Optional. A list of headers required to be present to validate, even if the signature is otherwise valid. Defaults to ['date'].
56-
:param method: Optional. The HTTP method used in the request (eg. "GET"). Required for the '(request-line)' header.
57-
:param path: Optional. The HTTP path requested, exactly as sent (including query arguments and fragments). Required for the '(request-line)' header.
56+
:param method: Optional. The HTTP method used in the request (eg. "GET"). Required for the '(request-target)' header.
57+
:param path: Optional. The HTTP path requested, exactly as sent (including query arguments and fragments). Required for the '(request-target)' header.
5858
:param host: Optional. The value to use for the Host header, if not supplied in :param:headers.
5959
"""
6060
required_headers = required_headers or ['date']

0 commit comments

Comments
 (0)