Commits

Andriy Kornatskyy committed 8679a26

Added demo for lockout feature.

Comments (0)

Files changed (8)

demos/template/content/templates-jinja2/membership/signin.html

                 <p>
                 <input type="submit" value="Sign In" />
                 </p>
+                <p><b>WARNING</b>: Your IP address will be blocked for <i>60 seconds</i> after <i>3 unsuccessful attempts</i>.
+                </p>
             </fieldset>
             <i><b>demo</b> user password is P@ssw0rd. You can press 'Ctrl'
                 + '1' to auto complete information.</i>

demos/template/content/templates-mako/membership/signin.html

                 <p>
                 <input type="submit" value="Sign In" />
                 </p>
+                <p><b>WARNING</b>: Your IP address will be blocked for <i>60 seconds</i> after <i>3 unsuccessful attempts</i>.
+                </p>
             </fieldset>
             <i><b>demo</b> user password is P@ssw0rd. You can press 'Ctrl'
                 + '1' to auto complete information.</i>

demos/template/content/templates-preprocessor/membership/signin.html

                 <p>
                 <input type="submit" value="Sign In" />
                 </p>
+
+                <p><b>WARNING</b>: Your IP address will be blocked for <i>60 seconds</i> after <i>3 unsuccessful attempts</i>.
+                </p>
             </fieldset>
             <i><b>demo</b> user password is P@@ssw0rd. You can press 'Ctrl'
                 + '1' to auto complete information.</i>

demos/template/content/templates-tenjin/membership/signin.html

                 <p>
                 <input type="submit" value="Sign In" />
                 </p>
+                <p><b>WARNING</b>: Your IP address will be blocked for <i>60 seconds</i> after <i>3 unsuccessful attempts</i>.
+                </p>
             </fieldset>
             <i><b>demo</b> user password is P@ssw0rd. You can press 'Ctrl'
                 + '1' to auto complete information.</i>

demos/template/content/templates-wheezy/membership/signin.html

                 <p>
                 <input type="submit" value="Sign In" />
                 </p>
+                <p><b>WARNING</b>: Your IP address will be blocked for <i>60 seconds</i> after <i>3 unsuccessful attempts</i>.
+                </p>
             </fieldset>
             <i><b>demo</b> user password is P@@ssw0rd. You can press 'Ctrl'
                 + '1' to auto complete information.</i>

demos/template/i18n/en/LC_MESSAGES/membership.po

 msgstr ""
 "The system was unable to create an account for you. Please try again later."
 
-#: src/membership/web/views.py:125
+#: src/membership/web/views.py:133
 msgid ""
 "Your registration request has been queued. Please wait while your request "
 "will be processed. If your request fails please try again."

demos/template/src/lockout.py

+
+from datetime import timedelta
+
+from wheezy.caching.lockout import Counter
+from wheezy.caching.lockout import Locker
+from wheezy.http.response import forbidden
+
+from config import cache
+
+
+# region: alerts
+
+def ignore_alert(s, name, counter):
+    pass
+
+
+# region: lockouts and defaults
+
+def lockout_by_id(count=10,
+                  period=timedelta(minutes=15),
+                  duration=timedelta(hours=1),
+                  reset=False,
+                  alert=ignore_alert):
+    key_func = lambda h: 'id:%s' % h.principal.id
+    return Counter(key_func=key_func, count=count,
+                   period=period, duration=duration,
+                   reset=reset, alert=alert)
+
+
+def lockout_by_ip(count=10,
+                  period=timedelta(minutes=10),
+                  duration=timedelta(hours=2),
+                  reset=True,
+                  alert=ignore_alert):
+    key_func = lambda h: 'ip:%s' % h.request.environ['REMOTE_ADDR']
+    return Counter(key_func=key_func, count=count,
+                   period=period, duration=duration,
+                   reset=reset, alert=alert)
+
+
+def lockout_by_id_ip(count=10,
+                     period=timedelta(minutes=20),
+                     duration=timedelta(hours=1),
+                     reset=True,
+                     alert=ignore_alert):
+    key_func = lambda h: 'idip:%s:%s' % (
+        h.principal.id, h.request.environ['REMOTE_ADDR'])
+    return Counter(key_func=key_func, count=count,
+                   period=period, duration=duration,
+                   reset=reset, alert=alert)
+
+
+# region: config
+
+locker = Locker(cache, key_prefix='mysite',
+                forbid_action=lambda s: forbidden(),
+                by_id=lockout_by_id,
+                by_ip=lockout_by_ip,
+                by_id_ip=lockout_by_id_ip)

demos/template/src/membership/web/views.py

 from wheezy.web import handler_cache
 from wheezy.web.handlers import BaseHandler
 
+from lockout import locker
 from factory import Factory
 from membership.models import Credential
 from membership.models import Registration
 
 class SignInHandler(BaseHandler):
 
+    lockout = locker.define(
+        name='signin attempts',
+        by_ip=dict(count=3, duration=60)
+    )
+
     @attribute
     def model(self):
         return attrdict({
             credential=credential,
             model=self.model)
 
+    @lockout.forbid_locked
     def post(self):
         if not self.validate_xsrf_token():
             return self.redirect_for(self.route_args.route_name)
         del self.xsrf_token
         return self.see_other_for('default')
 
+    @lockout.guard
     def authenticate(self, credential):
         #with self.factory as f:
         f = self.factory.__enter__()