Skip to content

Commit

Permalink
Merge pull request #79 from level12/11-rate-limit
Browse files Browse the repository at this point in the history
Add rate limiting on particular views
  • Loading branch information
guruofgentoo committed Apr 16, 2020
2 parents dde1b63 + be73a1b commit 0725f93
Show file tree
Hide file tree
Showing 17 changed files with 970 additions and 77 deletions.
1 change: 1 addition & 0 deletions keg_auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
UserMixin,
UserEmailMixin,
UserTokenMixin,
AttemptMixin,
PermissionMixin,
GroupMixin,
BundleMixin,
Expand Down
25 changes: 24 additions & 1 deletion keg_auth/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import click
import keg

from keg_auth.model import get_username_key
from keg_auth.extensions import gettext as _
from keg_auth.model.entity_registry import RegistryError


def add_cli_to_app(app, cli_group_name, user_args=['email']):
Expand All @@ -14,7 +16,7 @@ def auth():
@click.argument('username')
def set_user_password(username):
user_ent = app.auth_manager.entity_registry.user_cls
user = user_ent.get_by(username=username)
user = user_ent.get_by(**{get_username_key(user_ent): username})
if user is None:
click.echo('Unknown user', err=True)
return
Expand Down Expand Up @@ -50,4 +52,25 @@ def _create_user(as_superuser, no_mail, **kwargs):
create_user = click.argument(arg)(create_user)
auth.command('create-user')(create_user)

@click.option('--username', '--user', help='username to filter by')
@click.option('--older-than', type=int, help='number of days')
@click.option('--attempt-type', '--type', help='[login, reset, forgot]')
def purge_attempts(username, older_than, attempt_type):
"""Purge authentication attempts optionally filtered by username, type, or age."""
auth_manager = keg.current_app.auth_manager
try:
attempt_ent = auth_manager.entity_registry.attempt_cls
except RegistryError:
click.echo('No attempt class has been registered.')
return

count = attempt_ent.purge_attempts(
username=username,
older_than=older_than,
attempt_type=attempt_type
)
click.echo(f'Deleted {count} attempts.')

auth.command('purge-attempts')(purge_attempts)

app.auth_manager.cli_group = auth
16 changes: 16 additions & 0 deletions keg_auth/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,22 @@ def init_config(self, app):
app.config.setdefault('OIDC_USERINFO_URI', '/oauth2/userinfo')
app.config.setdefault('KEGAUTH_OIDC_LOGOUT_REDIRECT', None)

# Attempt lockout parameters.
# - Limit: maximum number of attempts within the timespan.
# - Timespan: number of seconds in which the limit can be reached.
# - Lockout: number of seconds until an attempt can be made after the limit is reached.
# - KEGAUTH_ATTEMPT_IP_LIMIT: base locking on IP address as well as input
app.config.setdefault('KEGAUTH_LOGIN_ATTEMPT_LIMIT', 3)
app.config.setdefault('KEGAUTH_LOGIN_ATTEMPT_TIMESPAN', 3600) # 1 hour
app.config.setdefault('KEGAUTH_LOGIN_ATTEMPT_LOCKOUT', 3600) # 1 hour
app.config.setdefault('KEGAUTH_FORGOT_ATTEMPT_LIMIT', 5)
app.config.setdefault('KEGAUTH_FORGOT_ATTEMPT_TIMESPAN', 3600) # 1 hour
app.config.setdefault('KEGAUTH_FORGOT_ATTEMPT_LOCKOUT', 3600) # 1 hour
app.config.setdefault('KEGAUTH_RESET_ATTEMPT_LIMIT', 1)
app.config.setdefault('KEGAUTH_RESET_ATTEMPT_TIMESPAN', 86400) # 24 hours
app.config.setdefault('KEGAUTH_RESET_ATTEMPT_LOCKOUT', 86400) # 24 hours
app.config.setdefault('KEGAUTH_ATTEMPT_IP_LIMIT', False)

def init_cli(self, app):
keg_auth.cli.add_cli_to_app(app, self.cli_group_name,
user_args=app.config.get('KEGAUTH_CLI_USER_ARGS'))
Expand Down
Binary file modified keg_auth/i18n/es/LC_MESSAGES/keg_auth.mo
Binary file not shown.
66 changes: 39 additions & 27 deletions keg_auth/i18n/es/LC_MESSAGES/keg_auth.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Keg Auth 0.2.0\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2020-04-02 09:17-0400\n"
"POT-Creation-Date: 2020-04-09 15:26-0400\n"
"PO-Revision-Date: 2018-08-23 13:49-0400\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: es\n"
Expand All @@ -18,15 +18,15 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.6.0\n"

#: keg_auth/cli.py:39
#: keg_auth/cli.py:41
msgid "User created."
msgstr "Creado por el usuario."

#: keg_auth/cli.py:42
#: keg_auth/cli.py:44
msgid "Email sent with verification URL."
msgstr "Correo electrónico enviado con la URL de verificación."

#: keg_auth/cli.py:44
#: keg_auth/cli.py:46
msgid "Verification URL: {url}"
msgstr "URL de verificación: {url}"

Expand Down Expand Up @@ -167,11 +167,11 @@ msgstr "Manojos"
msgid "Permissions"
msgstr "Permisos"

#: keg_auth/libs/authenticators.py:117
#: keg_auth/libs/authenticators.py:122
msgid "No user account matches: {}"
msgstr "Ninguna cuenta de usuario coincide: {}"

#: keg_auth/libs/authenticators.py:118
#: keg_auth/libs/authenticators.py:123
msgid ""
"The user account \"{}\" has an unverified email address. Please check "
"your email for a verification link from this website. Or, use the "
Expand All @@ -182,87 +182,99 @@ msgstr ""
"verificación desde este sitio web. O bien, use el enlace \"olvidó la "
"contraseña\" para verificar la cuenta."

#: keg_auth/libs/authenticators.py:123
#: keg_auth/libs/authenticators.py:128
msgid ""
"The user account \"{}\" has been disabled. Please contact this site's "
"administrators for more information."
msgstr ""
"La cuenta de usuario \"{}\" ha sido desactivada. Por favor, póngase en "
"contacto con los administradores de este sitio para más información."

#: keg_auth/libs/authenticators.py:154
#: keg_auth/libs/authenticators.py:159
msgid "Login successful."
msgstr "Inicio de sesión correcto."

#: keg_auth/libs/authenticators.py:186
#: keg_auth/libs/authenticators.py:191
msgid "The form has errors, please see below."
msgstr "El formulario tiene errores, ve a continuación."

#: keg_auth/libs/authenticators.py:223
#: keg_auth/libs/authenticators.py:331
msgid ""
"Authentication token was invalid or expired. Please fill out the form "
"below to get a new token."
msgstr ""
"El token de autenticación no es válido o ha caducado. Complete el "
"formulario a continuación para obtener un nuevo token."

#: keg_auth/libs/authenticators.py:273
#: keg_auth/libs/authenticators.py:381
msgid "Complete Password Reset"
msgstr "Restablecer Contraseña Completa"

#: keg_auth/libs/authenticators.py:274
#: keg_auth/libs/authenticators.py:382
msgid "Change Password"
msgstr "Cambia la Contraseña"

#: keg_auth/libs/authenticators.py:275
#: keg_auth/libs/authenticators.py:383
msgid "Password changed. Please use the new password to login below."
msgstr ""
"Contraseña cambiada. Utilice la nueva contraseña para iniciar sesión a "
"continuación."

#: keg_auth/libs/authenticators.py:282
#: keg_auth/libs/authenticators.py:400
msgid "Too many password reset attempts."
msgstr "Demasiados intentos de restablecimiento de contraseña."

#: keg_auth/libs/authenticators.py:438
msgid "Verify Account & Set Password"
msgstr "Verificar Cuenta y Establecer Contraseña"

#: keg_auth/libs/authenticators.py:283
#: keg_auth/libs/authenticators.py:439
msgid "Verify & Set Password"
msgstr "Verificar y Configurar la Contraseña"

#: keg_auth/libs/authenticators.py:284
#: keg_auth/libs/authenticators.py:440
msgid ""
"Account verified & password set. Please use the new password to login "
"below."
msgstr ""
"Cuenta verificada y contraseña establecida. Utilice la nueva contraseña "
"para iniciar sesión a continuación."

#: keg_auth/libs/authenticators.py:292
#: keg_auth/libs/authenticators.py:449
msgid "Log In"
msgstr "Iniciar Sesión"

#: keg_auth/libs/authenticators.py:293
#: keg_auth/libs/authenticators.py:450
msgid "Invalid password."
msgstr "Contraseña invalida."

#: keg_auth/libs/authenticators.py:321
#: keg_auth/libs/authenticators.py:497
msgid "Too many failed login attempts."
msgstr "Demasiados intentos fallidos de inicio de sesión."

#: keg_auth/libs/authenticators.py:557
msgid "Initiate Password Reset"
msgstr "Iniciar Restablecimiento de Contraseña"

#: keg_auth/libs/authenticators.py:323
#: keg_auth/libs/authenticators.py:559
msgid "Please check your email for the link to change your password."
msgstr ""
"Por favor revise su correo electrónico para ver el enlace para cambiar su"
" contraseña."

#: keg_auth/libs/authenticators.py:356
#: keg_auth/libs/authenticators.py:604
msgid "Too many failed attempts."
msgstr "Demasiados intentos fallidos."

#: keg_auth/libs/authenticators.py:661
msgid "You have been logged out."
msgstr "Has sido desconectado."

#: keg_auth/libs/authenticators.py:451
#: keg_auth/libs/authenticators.py:756
msgid "No KEGAUTH_LDAP_SERVER_URL configured!"
msgstr "¡No se configuró KEGAUTH_LDAP_SERVER_URL!"

#: keg_auth/libs/authenticators.py:455
#: keg_auth/libs/authenticators.py:760
msgid "No KEGAUTH_LDAP_DN_FORMAT configured!"
msgstr "¡No se configuró KEGAUTH_LDAP_DN_FORMAT!"

Expand All @@ -283,19 +295,19 @@ msgstr "El punto final {} en la navegación no está registrado"
msgid "must provide a NavURL or a list of NavItems"
msgstr "debe proporcionar un NavURL o una lista de NavItems"

#: keg_auth/model/entity_registry.py:24
#: keg_auth/model/entity_registry.py:25
msgid "Entity class already registered for {}"
msgstr "Clase de entidad ya registrada para {}"

#: keg_auth/model/entity_registry.py:26 keg_auth/model/entity_registry.py:50
#: keg_auth/model/entity_registry.py:27 keg_auth/model/entity_registry.py:54
msgid "Attempting to register unknown type {}"
msgstr "Intentando registrar el tipo desconocido {}"

#: keg_auth/model/entity_registry.py:28
#: keg_auth/model/entity_registry.py:29
msgid "Entity must be a class"
msgstr "La entidad debe ser una clase"

#: keg_auth/model/entity_registry.py:53
#: keg_auth/model/entity_registry.py:57
msgid "No entity registered for {}"
msgstr "Ninguna entidad registrada para {}"

Expand Down

0 comments on commit 0725f93

Please sign in to comment.