Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2012-03-09 13:40:06 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2012-03-09 15:37:16 (GMT)
commitc25b7f068ea5330bea8da998e98ef65f883293ac (patch)
treecbc12c2e6db117f22fc98164d13453cdeac65ab5
parent7d12d64605cb73b228af7dde83ec6e0f35dd2d17 (diff)
Simplify authentication sceme by cheking creds on every request
-rw-r--r--restful_document/env.py26
-rw-r--r--restful_document/router.py26
-rw-r--r--tests/__init__.py37
-rwxr-xr-xtests/units/document.py113
-rwxr-xr-xtests/units/user.py66
5 files changed, 158 insertions, 110 deletions
diff --git a/restful_document/env.py b/restful_document/env.py
index 306c218..bdab624 100644
--- a/restful_document/env.py
+++ b/restful_document/env.py
@@ -52,6 +52,10 @@ rundir = util.Option(
_('path to the directory to place pid files'),
default='/var/run/sugar-network')
+auth = util.Option(
+ _('authenticate requests using Sugar credentials'),
+ default=True, type_cast=util.Option.bool_cast, action='store_true')
+
trust_users = util.Option(
_('switch off user credentials check; disabling this option will ' \
'require OpenSSH-5.6 or later.'),
@@ -213,26 +217,8 @@ class Responce(threading.local):
class Principal(threading.local):
"""Authenticated user."""
- _cache = {}
- _user = None
-
- @property
- def user(self):
- self.authenticate()
- return self._user
-
- def authenticate(self):
- if self._user is not None:
- return
- enforce('sugar_user' in request and 'sugar_user_signature' in request,
- Unauthorized, _('Sugar user credentials were not specified'))
- signature = request['sugar_user_signature']
- user = self._cache.get(signature)
- if user is None:
- from restful_document.user import User
- User.verify(request['sugar_user'], signature)
- user = self._cache[signature] = request['sugar_user']
- self._user = user
+ user = None
+ authenticated = set()
request = Request()
diff --git a/restful_document/router.py b/restful_document/router.py
index ab95f26..99dd24f 100644
--- a/restful_document/router.py
+++ b/restful_document/router.py
@@ -42,16 +42,17 @@ class Router(object):
env.request.set(environ)
env.responce.set()
- _logger.debug('Processing request %s: %s',
- env.request.url, env.request.content)
+ _logger.debug('Processing %s request %s: %s',
+ env.request.method, env.request.url,
+ env.request.content or '(no sent data)')
try:
+ _authenticate()
+
method = self._metadata.get_method()
enforce(method is not None and \
method.method == env.request.method, env.BadRequest,
_('No way to handle the request'))
- if method.method != 'GET':
- env.principal.authenticate()
result = method()
except Exception, error:
@@ -179,3 +180,20 @@ def _list_methods(classes):
else:
raise RuntimeError(_('Incorrect RESTful method for %r') % attr)
yield method_cls(cls, slot, attr, **attr.restful_cls_kwargs)
+
+
+def _authenticate():
+ enforce('sugar_user' in env.request and \
+ 'sugar_user_signature' in env.request, env.Unauthorized,
+ _('Sugar user credentials were not specified'))
+
+ user = env.request['sugar_user']
+ signature = env.request['sugar_user_signature']
+
+ if env.auth.value and signature not in env.principal.authenticated and \
+ (env.request.path != ['user'] or env.request.method != 'POST'):
+ from restful_document.user import User
+ User.verify(user, signature)
+ env.principal.authenticated.add(signature)
+
+ env.principal.user = user
diff --git a/tests/__init__.py b/tests/__init__.py
index eb78f41..07e1a70 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -5,11 +5,13 @@ import sys
import time
import signal
import shutil
+import hashlib
import logging
import unittest
from os.path import dirname, join, exists, abspath
import restkit
+from M2Crypto import DSA
import active_document as ad
@@ -164,3 +166,38 @@ class Resource(restkit.Resource):
if 'Content-Type' not in headers:
headers['Content-Type'] = 'application/json'
return restkit.Resource.delete(self, path, headers=headers, **kwargs)
+
+
+def sign(user):
+ key_path = ad.util.TempFilePath(text=DSS_PRIVKEY)
+ key = DSA.load_key(key_path)
+ return key.sign_asn1(hashlib.sha1(user).digest()).encode('hex')
+
+
+def creds():
+ return {'SUGAR_USER': UID_FOR_PUBKEY,
+ 'SUGAR_USER_SIGNATURE': sign(UID_FOR_PUBKEY),
+ }
+
+
+VALID_DSS_PUBKEY = """\
+ssh-dss AAAAB3NzaC1kc3MAAACBANuYoFH3uvJGoQFMeW6M3CCJQlPrSv6sqd9dGQlwnnNxLBrq6KgY63e10ULtyYzq9UjiIUowqbtheGrtPCtL5w7qmFcCnq1cFzAk6Xxfe6ytJDx1fql5Y1wKqa+zxOKF6SGNnglyxvf78mZXt2G6wx22AjW+1fEhAOr+g8kRiUbBAAAAFQDA/W3LfD5NBB4vlZFcT10jU4B8QwAAAIBHh1U2B71memu/TsatwOo9+CyUyvF0FHHsXwQDkeRjqY3dcfeV38YoU/EbOZtHIQgdfGrzy7m5osnpBwUtHLunZJuwCt5tBNrpU8CAF7nEXOJ4n2FnoNiWO1IsbWdhkh9Hd7+TBM9hLGmOqlqTIx3TmUG0e4F2X33VVJ8UsrJ3mwAAAIEAm29WVw9zkRbv6CTFhPlLjJ71l/2GE9XFbdznJFRmPNBBWF2J452okRWywzeDMIIoi/z0wmNSr2B6P9wduxSxp8eIWQhKVQa4V4lJyqX/A2tE5SQtFULtw3yiYOUaCjvB2s46ZM6/9K3r8o7FSKHDpYlqAbBKURNCot5zDAu6RgE=
+"""
+INVALID_DSS_PUBKEY = """\
+ssh-dss ____B3NzaC1kc3MAAACBANuYoFH3uvJGoQFMeW6M3CCJQlPrSv6sqd9dGQlwnnNxLBrq6KgY63e10ULtyYzq9UjiIUowqbtheGrtPCtL5w7qmFcCnq1cFzAk6Xxfe6ytJDx1fql5Y1wKqa+zxOKF6SGNnglyxvf78mZXt2G6wx22AjW+1fEhAOr+g8kRiUbBAAAAFQDA/W3LfD5NBB4vlZFcT10jU4B8QwAAAIBHh1U2B71memu/TsatwOo9+CyUyvF0FHHsXwQDkeRjqY3dcfeV38YoU/EbOZtHIQgdfGrzy7m5osnpBwUtHLunZJuwCt5tBNrpU8CAF7nEXOJ4n2FnoNiWO1IsbWdhkh9Hd7+TBM9hLGmOqlqTIx3TmUG0e4F2X33VVJ8UsrJ3mwAAAIEAm29WVw9zkRbv6CTFhPlLjJ71l/2GE9XFbdznJFRmPNBBWF2J452okRWywzeDMIIoi/z0wmNSr2B6P9wduxSxp8eIWQhKVQa4V4lJyqX/A2tE5SQtFULtw3yiYOUaCjvB2s46ZM6/9K3r8o7FSKHDpYlqAbBKURNCot5zDAu6RgE=
+"""
+DSS_PRIVKEY = """\
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDbmKBR97ryRqEBTHlujNwgiUJT60r+rKnfXRkJcJ5zcSwa6uio
+GOt3tdFC7cmM6vVI4iFKMKm7YXhq7TwrS+cO6phXAp6tXBcwJOl8X3usrSQ8dX6p
+eWNcCqmvs8TihekhjZ4Jcsb3+/JmV7dhusMdtgI1vtXxIQDq/oPJEYlGwQIVAMD9
+bct8Pk0EHi+VkVxPXSNTgHxDAoGAR4dVNge9Znprv07GrcDqPfgslMrxdBRx7F8E
+A5HkY6mN3XH3ld/GKFPxGzmbRyEIHXxq88u5uaLJ6QcFLRy7p2SbsArebQTa6VPA
+gBe5xFzieJ9hZ6DYljtSLG1nYZIfR3e/kwTPYSxpjqpakyMd05lBtHuBdl991VSf
+FLKyd5sCgYEAm29WVw9zkRbv6CTFhPlLjJ71l/2GE9XFbdznJFRmPNBBWF2J452o
+kRWywzeDMIIoi/z0wmNSr2B6P9wduxSxp8eIWQhKVQa4V4lJyqX/A2tE5SQtFULt
+w3yiYOUaCjvB2s46ZM6/9K3r8o7FSKHDpYlqAbBKURNCot5zDAu6RgECFQC6wU/U
+6uUSSSw8Apr+eJQlSFhA+Q==
+-----END DSA PRIVATE KEY-----
+"""
+UID_FOR_PUBKEY = '25c081e29242cf7a19ae893a420ab3de56e9e989'
diff --git a/tests/units/document.py b/tests/units/document.py
index 77a8d4e..348d8c7 100755
--- a/tests/units/document.py
+++ b/tests/units/document.py
@@ -44,17 +44,28 @@ class Document(rd.Document):
class DocumentTest(tests.Test):
def test_Walkthrough(self):
- self.httpd(8000, [Document])
+ self.httpd(8000, [rd.User, Document])
rest = Resource('http://localhost:8000')
+ props = {
+ 'nickname': 'foo',
+ 'pubkey': tests.VALID_DSS_PUBKEY,
+ 'color': '',
+ 'machine_sn': 'machine_sn',
+ 'machine_uuid': 'machine_uuid',
+ }
+ rest.post('/user', payload=json.dumps(props), headers=tests.creds())
+
guid_1 = json.loads(
- rest.post('/document', payload=json.dumps({
- 'term': 'term',
- 'stored': 'stored',
- })).body_string()
+ rest.post('/document', headers=tests.creds(),
+ payload=json.dumps({
+ 'term': 'term',
+ 'stored': 'stored',
+ })
+ ).body_string()
)['guid']
- reply = json.loads(rest.get('/document/' + guid_1).body_string())
+ reply = json.loads(rest.get('/document/' + guid_1, headers=tests.creds()).body_string())
del reply['ctime']
del reply['mtime']
self.assertEqual(
@@ -67,13 +78,15 @@ class DocumentTest(tests.Test):
reply)
guid_2 = json.loads(
- rest.post('/document', payload=json.dumps({
- 'term': 'term2',
- 'stored': 'stored2',
- })).body_string()
+ rest.post('/document', headers=tests.creds(),
+ payload=json.dumps({
+ 'term': 'term2',
+ 'stored': 'stored2',
+ })
+ ).body_string()
)['guid']
- reply = json.loads(rest.get('/document/' + guid_2).body_string())
+ reply = json.loads(rest.get('/document/' + guid_2, headers=tests.creds()).body_string())
del reply['ctime']
del reply['mtime']
self.assertEqual(
@@ -85,7 +98,7 @@ class DocumentTest(tests.Test):
},
reply)
- reply = json.loads(rest.get('/document', reply='guid,stored,term,vote,counter').body_string())
+ reply = json.loads(rest.get('/document', reply='guid,stored,term,vote,counter', headers=tests.creds()).body_string())
self.assertEqual(2, reply['total'])
self.assertEqual(
sorted([
@@ -94,16 +107,18 @@ class DocumentTest(tests.Test):
]),
sorted(reply['result']))
- rest.put('/document/' + guid_2, payload=json.dumps({
- 'vote': True,
- 'stored': 'stored3',
- 'term': 'term3',
- }))
+ rest.put('/document/' + guid_2, headers=tests.creds(),
+ payload=json.dumps({
+ 'vote': True,
+ 'stored': 'stored3',
+ 'term': 'term3',
+ })
+ )
# Let server process commit and change `counter` property
time.sleep(3)
- reply = json.loads(rest.get('/document/' + guid_2).body_string())
+ reply = json.loads(rest.get('/document/' + guid_2, headers=tests.creds()).body_string())
del reply['ctime']
del reply['mtime']
self.assertEqual(
@@ -121,9 +136,9 @@ class DocumentTest(tests.Test):
{'guid': guid_1, 'stored': 'stored', 'term': 'term', 'vote': False, 'counter': 0},
{'guid': guid_2, 'stored': 'stored3', 'term': 'term3', 'vote': True, 'counter': 1},
])},
- json.loads(rest.get('/document', reply='guid,stored,term,vote,counter').body_string()))
+ json.loads(rest.get('/document', reply='guid,stored,term,vote,counter', headers=tests.creds()).body_string()))
- rest.delete('/document/' + guid_1)
+ rest.delete('/document/' + guid_1, headers=tests.creds())
# Let server process commit and change `counter` property
time.sleep(3)
@@ -133,23 +148,24 @@ class DocumentTest(tests.Test):
'result': sorted([
{'guid': guid_2, 'stored': 'stored3', 'term': 'term3', 'vote': True, 'counter': 1},
])},
- json.loads(rest.get('/document', reply='guid,stored,term,vote,counter').body_string()))
+ json.loads(rest.get('/document', reply='guid,stored,term,vote,counter', headers=tests.creds()).body_string()))
self.assertEqual(
'term3',
- json.loads(rest.get('/document/' + guid_2 + '/term').body_string()))
- rest.put('/document/' + guid_2 + '/term', payload=json.dumps('term4'))
+ json.loads(rest.get('/document/' + guid_2 + '/term', headers=tests.creds()).body_string()))
+ rest.put('/document/' + guid_2 + '/term', payload=json.dumps('term4'), headers=tests.creds())
self.assertEqual(
'term4',
- json.loads(rest.get('/document/' + guid_2 + '/term').body_string()))
+ json.loads(rest.get('/document/' + guid_2 + '/term', headers=tests.creds()).body_string()))
- rest.put('/document/' + guid_2 + '/blob', payload='blob',
- headers={'Content-Type': 'application/octet-stream'})
+ headers = tests.creds()
+ headers['Content-Type'] = 'application/octet-stream'
+ rest.put('/document/' + guid_2 + '/blob', payload='blob', headers=headers)
self.assertEqual(
'blob',
- rest.get('/document/' + guid_2 + '/blob').body_string())
+ rest.get('/document/' + guid_2 + '/blob', headers=tests.creds()).body_string())
- rest.delete('/document/' + guid_2)
+ rest.delete('/document/' + guid_2, headers=tests.creds())
# Let server process commit and change `counter` property
time.sleep(3)
@@ -157,28 +173,41 @@ class DocumentTest(tests.Test):
self.assertEqual(
{'total': 0,
'result': sorted([])},
- json.loads(rest.get('/document', reply='guid,stored,term,vote,counter').body_string()))
+ json.loads(rest.get('/document', reply='guid,stored,term,vote,counter', headers=tests.creds()).body_string()))
def test_ServerCrash(self):
- self.httpd(8000, [Document])
+ self.httpd(8000, [rd.User, Document])
rest = Resource('http://localhost:8000')
+ props = {
+ 'nickname': 'foo',
+ 'color': '',
+ 'machine_sn': 'machine_sn',
+ 'machine_uuid': 'machine_uuid',
+ 'pubkey': tests.VALID_DSS_PUBKEY,
+ }
+ rest.post('/user', payload=json.dumps(props), headers=tests.creds())
+
guid_1 = json.loads(
- rest.post('/document', payload=json.dumps({
- 'term': 'term',
- 'stored': 'stored',
- })).body_string()
+ rest.post('/document', headers=tests.creds(),
+ payload=json.dumps({
+ 'term': 'term',
+ 'stored': 'stored',
+ })
+ ).body_string()
)['guid']
guid_2 = json.loads(
- rest.post('/document', payload=json.dumps({
- 'term': 'term2',
- 'stored': 'stored2',
- 'vote': '1',
- })).body_string()
+ rest.post('/document', headers=tests.creds(),
+ payload=json.dumps({
+ 'term': 'term2',
+ 'stored': 'stored2',
+ 'vote': '1',
+ })
+ ).body_string()
)['guid']
- reply = json.loads(rest.get('/document', reply='guid,stored,term,vote').body_string())
+ reply = json.loads(rest.get('/document', reply='guid,stored,term,vote', headers=tests.creds()).body_string())
self.assertEqual(2, reply['total'])
self.assertEqual(
sorted([{'guid': guid_1, 'stored': 'stored', 'term': 'term', 'vote': False},
@@ -187,10 +216,10 @@ class DocumentTest(tests.Test):
sorted(reply['result']))
self.httpdown(8000)
- self.httpd(8001, [Document])
+ self.httpd(8001, [rd.User, Document])
rest = Resource('http://localhost:8001')
- reply = json.loads(rest.get('/document', reply='guid,stored,term,vote,counter').body_string())
+ reply = json.loads(rest.get('/document', reply='guid,stored,term,vote,counter', headers=tests.creds()).body_string())
self.assertEqual(2, reply['total'])
self.assertEqual(
sorted([{'guid': guid_1, 'stored': 'stored', 'term': 'term', 'vote': False, 'counter': 0},
diff --git a/tests/units/user.py b/tests/units/user.py
index d41d1d8..c576000 100755
--- a/tests/units/user.py
+++ b/tests/units/user.py
@@ -2,26 +2,23 @@
# sugar-lint: disable
import json
-import hashlib
import restkit
-from M2Crypto import DSA
from __init__ import tests
from tests import Resource
import restful_document as rd
import active_document as ad
-util = ad.util
-from restful_document import env
+from restful_document import env, router
class UserTest(tests.Test):
def setUp(self):
tests.Test.setUp(self)
- env.principal._cache.clear()
+ env.principal.authenticated.clear()
env.request.environ = {}
def test_Register(self):
@@ -35,64 +32,45 @@ class UserTest(tests.Test):
'machine_uuid': 'machine_uuid',
}
- props['pubkey'] = INVALID_DSS_PUBKEY
- self.assertRaises(restkit.Unauthorized, rest.post, '/user', payload=json.dumps(props))
+ props['pubkey'] = tests.INVALID_DSS_PUBKEY
+ self.assertRaises(restkit.Unauthorized, rest.post, '/user', payload=json.dumps(props), headers=tests.creds())
- props['pubkey'] = VALID_DSS_PUBKEY
- reply = json.loads(
- rest.post('/user', payload=json.dumps(props)).body_string())
- self.assertEqual(UID_FOR_PUBKEY, reply['guid'])
+ props['pubkey'] = tests.VALID_DSS_PUBKEY
+ reply = json.loads(rest.post('/user', payload=json.dumps(props), headers=tests.creds()).body_string())
+ self.assertEqual(tests.UID_FOR_PUBKEY, reply['guid'])
def test_Authenticate(self):
def set_headers(user):
- key_path = util.TempFilePath(text=DSS_PRIVKEY)
- key = DSA.load_key(key_path)
- signature = key.sign_asn1(hashlib.sha1(user).digest()).encode('hex')
env.request.environ['HTTP_SUGAR_USER'] = user
- env.request.environ['HTTP_SUGAR_USER_SIGNATURE'] = signature
+ env.request.environ['HTTP_SUGAR_USER_SIGNATURE'] = tests.sign(user)
props = {
'nickname': 'foo',
'color': '',
'machine_sn': 'machine_sn',
'machine_uuid': 'machine_uuid',
- 'pubkey': VALID_DSS_PUBKEY,
+ 'pubkey': tests.VALID_DSS_PUBKEY,
}
self.httpd(8888, [rd.User])
rest = Resource('http://localhost:8888')
- rest.post('/user', payload=json.dumps(props))
+ rest.post('/user', payload=json.dumps(props), headers=tests.creds())
self.httpdown(8888)
with ad.Master([rd.User]):
+ env.principal.user = None
+
set_headers('foo')
- self.assertRaises(env.Unauthorized, lambda: env.principal.user)
-
- set_headers(UID_FOR_PUBKEY)
- self.assertEqual(UID_FOR_PUBKEY, env.principal.user)
-
-
-VALID_DSS_PUBKEY = """\
-ssh-dss AAAAB3NzaC1kc3MAAACBANuYoFH3uvJGoQFMeW6M3CCJQlPrSv6sqd9dGQlwnnNxLBrq6KgY63e10ULtyYzq9UjiIUowqbtheGrtPCtL5w7qmFcCnq1cFzAk6Xxfe6ytJDx1fql5Y1wKqa+zxOKF6SGNnglyxvf78mZXt2G6wx22AjW+1fEhAOr+g8kRiUbBAAAAFQDA/W3LfD5NBB4vlZFcT10jU4B8QwAAAIBHh1U2B71memu/TsatwOo9+CyUyvF0FHHsXwQDkeRjqY3dcfeV38YoU/EbOZtHIQgdfGrzy7m5osnpBwUtHLunZJuwCt5tBNrpU8CAF7nEXOJ4n2FnoNiWO1IsbWdhkh9Hd7+TBM9hLGmOqlqTIx3TmUG0e4F2X33VVJ8UsrJ3mwAAAIEAm29WVw9zkRbv6CTFhPlLjJ71l/2GE9XFbdznJFRmPNBBWF2J452okRWywzeDMIIoi/z0wmNSr2B6P9wduxSxp8eIWQhKVQa4V4lJyqX/A2tE5SQtFULtw3yiYOUaCjvB2s46ZM6/9K3r8o7FSKHDpYlqAbBKURNCot5zDAu6RgE=
-"""
-INVALID_DSS_PUBKEY = """\
-ssh-dss ____B3NzaC1kc3MAAACBANuYoFH3uvJGoQFMeW6M3CCJQlPrSv6sqd9dGQlwnnNxLBrq6KgY63e10ULtyYzq9UjiIUowqbtheGrtPCtL5w7qmFcCnq1cFzAk6Xxfe6ytJDx1fql5Y1wKqa+zxOKF6SGNnglyxvf78mZXt2G6wx22AjW+1fEhAOr+g8kRiUbBAAAAFQDA/W3LfD5NBB4vlZFcT10jU4B8QwAAAIBHh1U2B71memu/TsatwOo9+CyUyvF0FHHsXwQDkeRjqY3dcfeV38YoU/EbOZtHIQgdfGrzy7m5osnpBwUtHLunZJuwCt5tBNrpU8CAF7nEXOJ4n2FnoNiWO1IsbWdhkh9Hd7+TBM9hLGmOqlqTIx3TmUG0e4F2X33VVJ8UsrJ3mwAAAIEAm29WVw9zkRbv6CTFhPlLjJ71l/2GE9XFbdznJFRmPNBBWF2J452okRWywzeDMIIoi/z0wmNSr2B6P9wduxSxp8eIWQhKVQa4V4lJyqX/A2tE5SQtFULtw3yiYOUaCjvB2s46ZM6/9K3r8o7FSKHDpYlqAbBKURNCot5zDAu6RgE=
-"""
-DSS_PRIVKEY = """\
------BEGIN DSA PRIVATE KEY-----
-MIIBvAIBAAKBgQDbmKBR97ryRqEBTHlujNwgiUJT60r+rKnfXRkJcJ5zcSwa6uio
-GOt3tdFC7cmM6vVI4iFKMKm7YXhq7TwrS+cO6phXAp6tXBcwJOl8X3usrSQ8dX6p
-eWNcCqmvs8TihekhjZ4Jcsb3+/JmV7dhusMdtgI1vtXxIQDq/oPJEYlGwQIVAMD9
-bct8Pk0EHi+VkVxPXSNTgHxDAoGAR4dVNge9Znprv07GrcDqPfgslMrxdBRx7F8E
-A5HkY6mN3XH3ld/GKFPxGzmbRyEIHXxq88u5uaLJ6QcFLRy7p2SbsArebQTa6VPA
-gBe5xFzieJ9hZ6DYljtSLG1nYZIfR3e/kwTPYSxpjqpakyMd05lBtHuBdl991VSf
-FLKyd5sCgYEAm29WVw9zkRbv6CTFhPlLjJ71l/2GE9XFbdznJFRmPNBBWF2J452o
-kRWywzeDMIIoi/z0wmNSr2B6P9wduxSxp8eIWQhKVQa4V4lJyqX/A2tE5SQtFULt
-w3yiYOUaCjvB2s46ZM6/9K3r8o7FSKHDpYlqAbBKURNCot5zDAu6RgECFQC6wU/U
-6uUSSSw8Apr+eJQlSFhA+Q==
------END DSA PRIVATE KEY-----
-"""
-UID_FOR_PUBKEY = '25c081e29242cf7a19ae893a420ab3de56e9e989'
+ self.assertRaises(env.Unauthorized, router._authenticate)
+ self.assertEqual(None, env.principal.user)
+
+ set_headers(tests.UID_FOR_PUBKEY)
+ router._authenticate()
+ self.assertEqual(tests.UID_FOR_PUBKEY, env.principal.user)
+
+
+
+
if __name__ == '__main__':