Hi Michael. Excellent branch... the implementation and tests are all very clear. The only potential danger I can see with this branch is the ability to add unsafe regexes, but I don't see anyway around that unless we restricted ourselves to gmail accounts (ie. usesd settings.GMAIL_IDENTIFIER_WHITELIST and automatically calculated the regex to allow identifier+whatever). The only questions I've got below are for my own understanding or tiny style questions. I verified that all 611 tests pass. > === modified file 'identityprovider/models/captcha.py' > --- identityprovider/models/captcha.py 2011-06-30 04:55:13 +0000 > +++ identityprovider/models/captcha.py 2011-07-26 07:31:31 +0000 > @@ -190,3 +194,9 @@ > self._verified = False > raise VerifyCaptchaError(self.response.traceback) > return self._verified > + > + def check_whitelist(self, email): > + for pattern in settings.EMAIL_WHITELIST_REGEXP_LIST: > + if re.match(pattern, email): > + return True > + return False So that's the crux of the branch right? Nice and simple :) The only thought I had was whether it should be *outside* of captcha.verify(), rather than being hidden within, but that's just a small point - nothing to delay the branch landing over :) > > === modified file 'identityprovider/schema.py' > --- identityprovider/schema.py 2011-07-12 09:41:08 +0000 > +++ identityprovider/schema.py 2011-07-26 07:31:31 +0000 > @@ -78,6 +78,9 @@ > captcha.captcha_public_key = StringConfigOption() > captcha.captcha_private_key = StringConfigOption() > captcha.disable_captcha_verification = BoolConfigOption() > + captcha.email_whitelist_regexp_list = LinesConfigOption( > + item=StringConfigOption(raw=True) I wasn't sure at first why the raw=True was necessary, until I tried repr('^canonicaltest(?:\+.+)?@gmail\.com$'). > + ) > > # debug > debug = ConfigSection() > > === modified file 'identityprovider/tests/test_auth.py' > --- identityprovider/tests/test_auth.py 2011-07-15 15:17:19 +0000 > +++ identityprovider/tests/test_auth.py 2011-07-26 07:31:31 +0000 Great to fix up all the patch_object's :) > === modified file 'identityprovider/tests/test_captcha.py' > --- identityprovider/tests/test_captcha.py 2011-07-21 16:08:06 +0000 > +++ identityprovider/tests/test_captcha.py 2011-07-26 07:31:31 +0000 > === modified file 'identityprovider/tests/test_command_cleanup.py' > --- identityprovider/tests/test_command_cleanup.py 2011-07-15 11:50:53 +0000 > +++ identityprovider/tests/test_command_cleanup.py 2011-07-26 07:31:31 +0000 > === modified file 'identityprovider/tests/test_forms.py' > --- identityprovider/tests/test_forms.py 2011-07-15 11:50:53 +0000 > +++ identityprovider/tests/test_forms.py 2011-07-26 07:31:31 +0000 > @@ -18,6 +18,7 @@ > ) > from identityprovider.api10.forms import WebserviceCreateAccountForm > from identityprovider.models.openidmodels import OpenIDRPConfig > +from identityprovider.tests.utils import patch_settings > > from .utils import SSOBaseTestCase > > @@ -114,6 +115,23 @@ > self.assertTrue(form.is_valid()) > self.assertEqual(form.cleaned_data['platform'], 'desktop') > > + def test_captcha_checked_for_whitelist(self): > + data = { > + 'email': '