- Add a ``userid_checker`` argument to the auth_tkt identifier plugin,
courtesty of Gustavo Narea.
If ``userid_checker`` is provided, it must be a dotted Python name
that resolves to a function which accepts a userid and returns a
boolean True or False, indicating whether that user exists in a
database. This is a workaround. Due to a design bug in repoze.who,
the only way who can check for user existence is to use one or more
IAuthenticator plugin ``authenticate`` methods. If an
IAuthenticator's ``authenticate`` method returns true, it means that
the user exists. However most IAuthenticator plugins expect *both*
a username and a password, and will return False unconditionally if
both aren't supplied. This means that an authenticator can't be
used to check if the user "only" exists. The identity provided by
an auth_tkt does not contain a password to check against. The
actual design bug in repoze.who is this: when a user presents
credentials from an auth_tkt, he is considered "preauthenticated".
IAuthenticator.authenticate is just never called for a
"preauthenticated" identity, which works fine, but it means that the
user will be considered authenticated even if you deleted the user's
record from whatever database you happen to be using. However, if
you use a userid_checker, you can ensure that a user exists for the
auth_tkt supplied userid. If the userid_checker returns False, the
auth_tkt credentials are considered "no good".
| | |
| | | |
| | | - One-hundred percent unit test coverage. |
| | | |
| | | - Add ``timeout`` and ``reissue_time`` arguments to the auth_tkt |
| | | identifier plugin, courtesty of Paul Johnston. |
| | | |
| | | - Add a ``userid_checker`` argument to the auth_tkt identifier plugin, |
| | | courtesty of Gustavo Narea. |
| | | |
| | | If ``userid_checker`` is provided, it must be a dotted Python name |
| | | that resolves to a function which accepts a userid and returns a |
| | | boolean True or False, indicating whether that user exists in a |
| | | database. This is a workaround. Due to a design bug in repoze.who, |
| | | the only way who can check for user existence is to use one or more |
| | | IAuthenticator plugin ``authenticate`` methods. If an |
| | | IAuthenticator's ``authenticate`` method returns true, it means that |
| | | the user exists. However most IAuthenticator plugins expect *both* |
| | | a username and a password, and will return False unconditionally if |
| | | both aren't supplied. This means that an authenticator can't be |
| | | used to check if the user "only" exists. The identity provided by |
| | | an auth_tkt does not contain a password to check against. The |
| | | actual design bug in repoze.who is this: when a user presents |
| | | credentials from an auth_tkt, he is considered "preauthenticated". |
| | | IAuthenticator.authenticate is just never called for a |
| | | "preauthenticated" identity, which works fine, but it means that the |
| | | user will be considered authenticated even if you deleted the user's |
| | | record from whatever database you happen to be using. However, if |
| | | you use a userid_checker, you can ensure that a user exists for the |
| | | auth_tkt supplied userid. If the userid_checker returns False, the |
| | | auth_tkt credentials are considered "no good". |
| | | |
| | | 1.0.13 (2009/4/24) |
| | | ================== |
| | | |
| | |
| | | |
| | | .. module:: repoze.who.plugins.auth_tkt |
| | | |
| | | .. class:: AuthTktCookiePlugin(secret [, cookie_name='auth_tkt' [, secure=False [, include_ip=False [, timeout=None [, reissue_time=None]]]]]) |
| | | .. class:: AuthTktCookiePlugin(secret [, secretfile=None, [, cookie_name='auth_tkt' [, secure=False [, include_ip=False [, timeout=None [, reissue_time=None [, userid_checker=None]]]]]]]) |
| | | |
| | | An :class:`AuthTktCookiePlugin` is an ``IIdentifier`` plugin which |
| | | remembers its identity state in a client-side cookie. This plugin |
| | |
| | | be issued. If *timeout* is specified, you must also set |
| | | *reissue_time* to a lower value. |
| | | |
| | | If ``userid_checker`` is provided, it must be a dotted Python name |
| | | that resolves to a function which accepts a userid and returns a |
| | | boolean True or False, indicating whether that user exists in a |
| | | database. This is a workaround. Due to a design bug in repoze.who, |
| | | the only way who can check for user existence is to use one or more |
| | | IAuthenticator plugin ``authenticate`` methods. If an |
| | | IAuthenticator's ``authenticate`` method returns true, it means that |
| | | the user exists. However most IAuthenticator plugins expect *both* |
| | | a username and a password, and will return False unconditionally if |
| | | both aren't supplied. This means that an authenticator can't be |
| | | used to check if the user "only" exists. The identity provided by |
| | | an auth_tkt does not contain a password to check against. The |
| | | actual design bug in repoze.who is this: when a user presents |
| | | credentials from an auth_tkt, he is considered "preauthenticated". |
| | | IAuthenticator.authenticate is just never called for a |
| | | "preauthenticated" identity, which works fine, but it means that the |
| | | user will be considered authenticated even if you deleted the user's |
| | | record from whatever database you happen to be using. However, if |
| | | you use a userid_checker, you can ensure that a user exists for the |
| | | auth_tkt supplied userid. If the userid_checker returns False, the |
| | | auth_tkt credentials are considered "no good". |
| | | |
| | | .. note:: |
| | | Using the *include_ip* setting for public-facing applications may |
| | | cause problems for some users. `One study |
| | |
| | | |
| | | def __init__(self, secret, cookie_name='auth_tkt', |
| | | secure=False, include_ip=False, |
| | | timeout=None, reissue_time=None): |
| | | timeout=None, reissue_time=None, userid_checker=None): |
| | | self.secret = secret |
| | | self.cookie_name = cookie_name |
| | | self.include_ip = include_ip |
| | |
| | | 'be set to a lower value') |
| | | self.timeout = timeout |
| | | self.reissue_time = reissue_time |
| | | self.userid_checker = userid_checker |
| | | |
| | | # IIdentifier |
| | | def identify(self, environ): |
| | |
| | | timestamp, userid, tokens, user_data = auth_tkt.parse_ticket( |
| | | self.secret, cookie.value, remote_addr) |
| | | except auth_tkt.BadTicket: |
| | | return None |
| | | |
| | | if self.userid_checker and not self.userid_checker(userid): |
| | | return None |
| | | |
| | | if self.timeout and ( (timestamp + self.timeout) < time.time() ): |
| | |
| | | include_ip=False, |
| | | timeout=None, |
| | | reissue_time=None, |
| | | userid_checker=None, |
| | | ): |
| | | from repoze.who.utils import resolveDotted |
| | | if (secret is None and secretfile is None): |
| | | raise ValueError("One of 'secret' or 'secretfile' must not be None.") |
| | | if (secret is not None and secretfile is not None): |
| | |
| | | timeout = int(timeout) |
| | | if reissue_time: |
| | | reissue_time = int(reissue_time) |
| | | if userid_checker is not None: |
| | | userid_checker = resolveDotted(userid_checker) |
| | | plugin = AuthTktCookiePlugin(secret, |
| | | cookie_name, |
| | | _bool(secure), |
| | | _bool(include_ip), |
| | | timeout, |
| | | reissue_time, |
| | | userid_checker, |
| | | ) |
| | | return plugin |
| | | |
| | |
| | | self.assertEqual(plugin.timeout, 5) |
| | | self.assertEqual(plugin.reissue_time, 1) |
| | | |
| | | def test_factory_with_userid_checker(self): |
| | | from repoze.who.plugins.auth_tkt import make_plugin |
| | | plugin = make_plugin( |
| | | 'secret', |
| | | userid_checker='repoze.who.plugins.auth_tkt:make_plugin') |
| | | self.assertEqual(plugin.userid_checker, make_plugin) |
| | | |
| | | def test_timeout_no_reissue(self): |
| | | self.assertRaises(ValueError, self._makeOne, 'userid', timeout=1) |
| | | |
| | | def test_timeout_lower_than_reissue(self): |
| | | self.assertRaises(ValueError, self._makeOne, 'userid', timeout=1, |
| | | reissue_time=2) |
| | | |
| | | def test_identify_with_checker_and_existing_account(self): |
| | | plugin = self._makeOne('secret', userid_checker=dummy_userid_checker) |
| | | val = self._makeTicket(userid='existing') |
| | | environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val}) |
| | | result = plugin.identify(environ) |
| | | self.assertEqual(len(result), 4) |
| | | self.assertEqual(result['tokens'], ['']) |
| | | self.assertEqual(result['repoze.who.userid'], 'existing') |
| | | self.assertEqual(result['userdata'], 'userdata') |
| | | self.failUnless('timestamp' in result) |
| | | self.assertEqual(environ['REMOTE_USER_TOKENS'], ['']) |
| | | self.assertEqual(environ['REMOTE_USER_DATA'],'userdata') |
| | | self.assertEqual(environ['AUTH_TYPE'],'cookie') |
| | | |
| | | def test_identify_with_checker_and_non_existing_account(self): |
| | | plugin = self._makeOne('secret', userid_checker=dummy_userid_checker) |
| | | val = self._makeTicket(userid='nonexisting') |
| | | environ = self._makeEnviron({'HTTP_COOKIE':'auth_tkt=%s' % val}) |
| | | original_environ = environ.copy() |
| | | result = plugin.identify(environ) |
| | | self.assertEqual(result, None) |
| | | # The environ must not have been modified, excuding the paste.cookies |
| | | # variable: |
| | | del environ['paste.cookies'] |
| | | self.assertEqual(environ, original_environ) |
| | | |
| | | def dummy_userid_checker(userid): |
| | | return userid == 'existing' |