diff options
| author | Chris McDonough <chrism@plope.com> | 2010-12-31 17:15:43 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2010-12-31 17:15:43 -0500 |
| commit | 2526d8bdec3c2d84f3ab8ec1983150927fce7eae (patch) | |
| tree | 3ec747e24bb2ef94f2b933990051812d689474b2 | |
| parent | 95c95bf924a8c08e0a5b686d7a5d12fa4e49d87e (diff) | |
| download | pyramid-2526d8bdec3c2d84f3ab8ec1983150927fce7eae.tar.gz pyramid-2526d8bdec3c2d84f3ab8ec1983150927fce7eae.tar.bz2 pyramid-2526d8bdec3c2d84f3ab8ec1983150927fce7eae.zip | |
- The ``pyramid.interfaces.IAuthenticationPolicy`` interface now specifies an
``unauthenticated_userid`` method. This method supports an important
optimization required by people who are using persistent storages which do
not support object caching and whom want to create a "user object" as a
request attribute.
- A new API has been added to the ``pyramid.security`` module named
``unauthenticated_userid``. This API function calls the
``unauthenticated_userid`` method of the effective security policy.
- An ``unauthenticated_userid`` method has been added to the dummy
authentication policy returned by
``pyramid.config.Configurator.testing_securitypolicy``. It returns the
same thing as that the dummy authentication policy's
``authenticated_userid`` method.
- Since the ``pyramid.interfaces.IAuthenticationPolicy`` interface now
specifies that a policy implementation must implement an
``unauthenticated_userid`` method, all third-party custom authentication
policies now must implement this method. It, however, will only be called
when the global function named ``pyramid.security.unauthenticated_userid``
is invoked, so if you're not invoking that, you will not notice any issues.
- The (non-API) method of all internal authentication policy implementations
previously named ``_get_userid`` is now named ``unauthenticated_userid``,
promoted to an API method. If you were overriding this method, you'll now
need to override it as ``unauthenticated_userid`` instead.
| -rw-r--r-- | CHANGES.txt | 31 | ||||
| -rw-r--r-- | docs/api/security.rst | 2 | ||||
| -rw-r--r-- | pyramid/authentication.py | 14 | ||||
| -rw-r--r-- | pyramid/interfaces.py | 15 | ||||
| -rw-r--r-- | pyramid/security.py | 18 | ||||
| -rw-r--r-- | pyramid/testing.py | 8 | ||||
| -rw-r--r-- | pyramid/tests/test_authentication.py | 33 | ||||
| -rw-r--r-- | pyramid/tests/test_security.py | 33 | ||||
| -rw-r--r-- | pyramid/tests/test_testing.py | 6 |
9 files changed, 150 insertions, 10 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 826be0be6..19732a623 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -26,6 +26,32 @@ Features classmethod or staticmethod), use that as the decorator for each view registration for that handler. +- The ``pyramid.interfaces.IAuthenticationPolicy`` interface now specifies an + ``unauthenticated_userid`` method. This method supports an important + optimization required by people who are using persistent storages which do + not support object caching and whom want to create a "user object" as a + request attribute. + +- A new API has been added to the ``pyramid.security`` module named + ``unauthenticated_userid``. This API function calls the + ``unauthenticated_userid`` method of the effective security policy. + +- An ``unauthenticated_userid`` method has been added to the dummy + authentication policy returned by + ``pyramid.config.Configurator.testing_securitypolicy``. It returns the + same thing as that the dummy authentication policy's + ``authenticated_userid`` method. + +Backwards Incompatibilities +--------------------------- + +- Since the ``pyramid.interfaces.IAuthenticationPolicy`` interface now + specifies that a policy implementation must implement an + ``unauthenticated_userid`` method, all third-party custom authentication + policies now must implement this method. It, however, will only be called + when the global function named ``pyramid.security.unauthenticated_userid`` + is invoked, so if you're not invoking that, you will not notice any issues. + Documentation ------------- @@ -55,6 +81,11 @@ Internals ``__original_view__`` attribute which references the original view callable (or class). +- The (non-API) method of all internal authentication policy implementations + previously named ``_get_userid`` is now named ``unauthenticated_userid``, + promoted to an API method. If you were overriding this method, you'll now + need to override it as ``unauthenticated_userid`` instead. + 1.0a8 (2010-12-27) ================== diff --git a/docs/api/security.rst b/docs/api/security.rst index 4acf5fe4d..de249355d 100644 --- a/docs/api/security.rst +++ b/docs/api/security.rst @@ -10,6 +10,8 @@ Authentication API Functions .. autofunction:: authenticated_userid +.. autofunction:: unauthenticated_userid + .. autofunction:: effective_principals .. autofunction:: forget diff --git a/pyramid/authentication.py b/pyramid/authentication.py index 86d725bcf..e8ae48ed9 100644 --- a/pyramid/authentication.py +++ b/pyramid/authentication.py @@ -17,7 +17,7 @@ from pyramid.security import Everyone class CallbackAuthenticationPolicy(object): """ Abstract class """ def authenticated_userid(self, request): - userid = self._get_userid(request) + userid = self.unauthenticated_userid(request) if userid is None: return None if self.callback is None: @@ -27,7 +27,7 @@ class CallbackAuthenticationPolicy(object): def effective_principals(self, request): effective_principals = [Everyone] - userid = self._get_userid(request) + userid = self.unauthenticated_userid(request) if userid is None: return effective_principals if self.callback is None: @@ -89,6 +89,12 @@ class RepozeWho1AuthenticationPolicy(CallbackAuthenticationPolicy): if self.callback(identity, request) is not None: # is not None! return identity['repoze.who.userid'] + def unauthenticated_userid(self, request): + identity = self._get_identity(request) + if identity is None: + return None + return identity['repoze.who.userid'] + def effective_principals(self, request): effective_principals = [Everyone] identity = self._get_identity(request) @@ -147,7 +153,7 @@ class RemoteUserAuthenticationPolicy(CallbackAuthenticationPolicy): self.environ_key = environ_key self.callback = callback - def _get_userid(self, request): + def unauthenticated_userid(self, request): return request.environ.get(self.environ_key) def remember(self, request, principal, **kw): @@ -264,7 +270,7 @@ class AuthTktAuthenticationPolicy(CallbackAuthenticationPolicy): ) self.callback = callback - def _get_userid(self, request): + def unauthenticated_userid(self, request): result = self.cookie.identify(request) if result: return result['userid'] diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 10a324b28..0a6b39de4 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -155,8 +155,19 @@ class IRouteRequest(Interface): class IAuthenticationPolicy(Interface): """ An object representing a Pyramid authentication policy. """ def authenticated_userid(request): - """ Return the authenticated userid or ``None`` if no - authenticated userid can be found. """ + """ Return the authenticated userid or ``None`` if no authenticated + userid can be found. This method of the policy should ensure that a + record exists in whatever persistent store is used related to the + user (the user should not have been deleted); if a record associated + with the current id does not exist in a persistent store, it should + return ``None``.""" + + def unauthenticated_userid(request): + """ Return the *unauthenticated* userid. This method performs the + same duty as ``authenticated_userid`` but is permitted to return the + userid based only on data present in the request; it neednt (and + shouldn't) check any persistent store to ensure that the user record + related to the request userid exists.""" def effective_principals(request): """ Return a sequence representing the effective principals diff --git a/pyramid/security.py b/pyramid/security.py index 723e87a87..51c0802d5 100644 --- a/pyramid/security.py +++ b/pyramid/security.py @@ -64,6 +64,24 @@ def authenticated_userid(request): return None return policy.authenticated_userid(request) +def unauthenticated_userid(request): + """ Return an object which represents the *claimed* (not verified) user + id of the credentials present in the request. ``None`` if there is no + :term:`authentication policy` in effect or there is no user data + associated with the current request. This differs from + :func:`~pyramid.security.authenticated_userid`, because the effective + authentication policy will not ensure that a record associated with the + userid exists in persistent storage.""" + try: + reg = request.registry + except AttributeError: + reg = get_current_registry() # b/c + + policy = reg.queryUtility(IAuthenticationPolicy) + if policy is None: + return None + return policy.unauthenticated_userid(request) + def effective_principals(request): """ Return the list of 'effective' :term:`principal` identifiers for the ``request``. This will include the userid of the diff --git a/pyramid/testing.py b/pyramid/testing.py index 61bb1843a..15fc385cd 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -44,9 +44,10 @@ def registerDummySecurityPolicy(userid=None, groupids=(), permissive=True): :func:`pyramid.security.authenticated_userid` or :func:`pyramid.security.effective_principals` APIs are used. - This function is most useful when testing code that uses the APIs - named :func:`pyramid.security.has_permission`, + This function is most useful when testing code that uses the APIs named + :func:`pyramid.security.has_permission`, :func:`pyramid.security.authenticated_userid`, + :func:`pyramid.security.unauthenticated_userid`, :func:`pyramid.security.effective_principals`, and :func:`pyramid.security.principals_allowed_by_permission`. @@ -332,6 +333,9 @@ class DummySecurityPolicy(object): def authenticated_userid(self, request): return self.userid + def unauthenticated_userid(self, request): + return self.userid + def effective_principals(self, request): effective_principals = [Everyone] if self.userid: diff --git a/pyramid/tests/test_authentication.py b/pyramid/tests/test_authentication.py index d9d0c2c97..49d655466 100644 --- a/pyramid/tests/test_authentication.py +++ b/pyramid/tests/test_authentication.py @@ -18,11 +18,22 @@ class TestRepozeWho1AuthenticationPolicy(unittest.TestCase): from pyramid.interfaces import IAuthenticationPolicy verifyObject(IAuthenticationPolicy, self._makeOne()) + def test_unauthenticated_userid_returns_None(self): + request = DummyRequest({}) + policy = self._makeOne() + self.assertEqual(policy.unauthenticated_userid(request), None) + + def test_unauthenticated_userid(self): + request = DummyRequest( + {'repoze.who.identity':{'repoze.who.userid':'fred'}}) + policy = self._makeOne() + self.assertEqual(policy.unauthenticated_userid(request), 'fred') + def test_authenticated_userid_None(self): request = DummyRequest({}) policy = self._makeOne() self.assertEqual(policy.authenticated_userid(request), None) - + def test_authenticated_userid(self): request = DummyRequest( {'repoze.who.identity':{'repoze.who.userid':'fred'}}) @@ -132,6 +143,16 @@ class TestRemoteUserAuthenticationPolicy(unittest.TestCase): from pyramid.interfaces import IAuthenticationPolicy verifyObject(IAuthenticationPolicy, self._makeOne()) + def test_unauthenticated_userid_returns_None(self): + request = DummyRequest({}) + policy = self._makeOne() + self.assertEqual(policy.unauthenticated_userid(request), None) + + def test_unauthenticated_userid(self): + request = DummyRequest({'REMOTE_USER':'fred'}) + policy = self._makeOne() + self.assertEqual(policy.unauthenticated_userid(request), 'fred') + def test_authenticated_userid_None(self): request = DummyRequest({}) policy = self._makeOne() @@ -196,6 +217,16 @@ class TestAutkTktAuthenticationPolicy(unittest.TestCase): from pyramid.interfaces import IAuthenticationPolicy verifyObject(IAuthenticationPolicy, self._makeOne(None, None)) + def test_unauthenticated_userid_returns_None(self): + request = DummyRequest({}) + policy = self._makeOne(None, None) + self.assertEqual(policy.unauthenticated_userid(request), None) + + def test_unauthenticated_userid(self): + request = DummyRequest({'REMOTE_USER':'fred'}) + policy = self._makeOne(None, {'userid':'fred'}) + self.assertEqual(policy.unauthenticated_userid(request), 'fred') + def test_authenticated_userid_no_cookie_identity(self): request = DummyRequest({}) policy = self._makeOne(None, None) diff --git a/pyramid/tests/test_security.py b/pyramid/tests/test_security.py index dd9d48f45..94cefa642 100644 --- a/pyramid/tests/test_security.py +++ b/pyramid/tests/test_security.py @@ -224,6 +224,36 @@ class TestAuthenticatedUserId(unittest.TestCase): result = self._callFUT(request) self.assertEqual(result, 'yo') +class TestUnauthenticatedUserId(unittest.TestCase): + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + def _callFUT(self, request): + from pyramid.security import unauthenticated_userid + return unauthenticated_userid(request) + + def test_no_authentication_policy(self): + request = _makeRequest() + result = self._callFUT(request) + self.assertEqual(result, None) + + def test_with_authentication_policy(self): + request = _makeRequest() + _registerAuthenticationPolicy(request.registry, 'yo') + result = self._callFUT(request) + self.assertEqual(result, 'yo') + + def test_with_authentication_policy_no_reg_on_request(self): + from pyramid.threadlocal import get_current_registry + request = DummyRequest({}) + registry = get_current_registry() + _registerAuthenticationPolicy(registry, 'yo') + result = self._callFUT(request) + self.assertEqual(result, 'yo') + class TestEffectivePrincipals(unittest.TestCase): def setUp(self): cleanUp() @@ -355,6 +385,9 @@ class DummyAuthenticationPolicy: def effective_principals(self, request): return self.result + def unauthenticated_userid(self, request): + return self.result + def authenticated_userid(self, request): return self.result diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py index ec6fdac5f..d2ed957f2 100644 --- a/pyramid/tests/test_testing.py +++ b/pyramid/tests/test_testing.py @@ -297,7 +297,11 @@ class TestDummySecurityPolicy(unittest.TestCase): def test_authenticated_userid(self): policy = self._makeOne('user') self.assertEqual(policy.authenticated_userid(None), 'user') - + + def test_unauthenticated_userid(self): + policy = self._makeOne('user') + self.assertEqual(policy.unauthenticated_userid(None), 'user') + def test_effective_principals_userid(self): policy = self._makeOne('user', ('group1',)) from pyramid.security import Everyone |
