summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2010-12-31 17:15:43 -0500
committerChris McDonough <chrism@plope.com>2010-12-31 17:15:43 -0500
commit2526d8bdec3c2d84f3ab8ec1983150927fce7eae (patch)
tree3ec747e24bb2ef94f2b933990051812d689474b2
parent95c95bf924a8c08e0a5b686d7a5d12fa4e49d87e (diff)
downloadpyramid-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.txt31
-rw-r--r--docs/api/security.rst2
-rw-r--r--pyramid/authentication.py14
-rw-r--r--pyramid/interfaces.py15
-rw-r--r--pyramid/security.py18
-rw-r--r--pyramid/testing.py8
-rw-r--r--pyramid/tests/test_authentication.py33
-rw-r--r--pyramid/tests/test_security.py33
-rw-r--r--pyramid/tests/test_testing.py6
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