Skip to content
This repository has been archived by the owner on Jul 11, 2019. It is now read-only.

#455 hhu_theme Brute force protection #686

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/adhocracy/controllers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

from repoze.who.api import get_api

from datetime import datetime

from adhocracy import config
from adhocracy import forms, model
from adhocracy import i18n
Expand All @@ -45,10 +47,9 @@
from adhocracy.lib.templating import ret_success
from adhocracy.lib.queue import update_entity
from adhocracy.lib.util import get_entity_or_abort, random_token

from adhocracy.lib.event.types import (S_VOTE, S_DELEGATION, S_PROPOSAL,
S_COMMENT, S_PAGE, S_CONTRIBUTION)

import adhocracy.lib.util

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -1057,7 +1058,6 @@ def post_login(self):
else:
login_configuration = h.allowed_login_types()
error_message = _("Invalid login")

if 'username+password' in login_configuration:
if 'email+password' in login_configuration:
error_message = _("Invalid email / user name or password")
Expand All @@ -1066,7 +1066,6 @@ def post_login(self):
else:
if 'email+password' in login_configuration:
error_message = _("Invalid email or password")

return self._render_loginform(errors={"login": error_message})

def logout(self):
Expand Down
18 changes: 18 additions & 0 deletions src/adhocracy/lib/auth/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
from pylons import config
from webob import Request
from adhocracy.model.login import Login, login_table
from datetime import datetime
import adhocracy.lib.util
import time
import math

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -72,9 +77,22 @@ def authenticate(self, environ, identity):
user = self.get_user(identity['login'])

if user:
#count_logs return amount of unsuccessful logins for the past hour
amount = model.login.Login.count_logs(user.user_name)
ip = adhocracy.lib.util.get_client_ip(environ)
if (amount > 5):
time.sleep(pow(2, (amount-5)))
validator = getattr(user, self.translations['validate_password'])
if validator(identity['password']):
#user_log creates entry to loginlog
user_log = model.login.Login.create(datetime.utcnow(),
ip, user.user_name,
u'yes')
return user.user_name
#user_log creates entry to loginlog
user_log = model.login.Login.create(datetime.utcnow(),
ip, user.user_name,
u'no')


class EmailSQLAlchemyUserMDPlugin(_EmailBaseSQLAlchemyPlugin,
Expand Down
17 changes: 17 additions & 0 deletions src/adhocracy/migration/versions/076_login_store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from datetime import datetime
from sqlalchemy import MetaData, Table, Boolean, Column
from sqlalchemy import Integer, DateTime, Unicode, UnicodeText

meta = MetaData()

login_table = Table('loginlog', meta,
Column('access_time', DateTime, default=datetime.utcnow),
Column('ip_address', Unicode(255), nullable=True),
Column('user', UnicodeText()),
Column('success', UnicodeText())
)


def upgrade(migrate_engine):
meta.bind = migrate_engine
login_table.create()
18 changes: 18 additions & 0 deletions src/adhocracy/migration/versions/080_login_store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from datetime import datetime
from sqlalchemy import MetaData, Table, Boolean, Column
from sqlalchemy import Integer, DateTime, Unicode, UnicodeText

meta = MetaData()

login_table = Table(
'loginlog', meta,
Column('access_time', DateTime, default=datetime.utcnow),
Column('ip_address', Unicode(255), nullable=True),
Column('user', UnicodeText()),
Column('success', UnicodeText())
)


def upgrade(migrate_engine):
meta.bind = migrate_engine
login_table.create()
7 changes: 7 additions & 0 deletions src/adhocracy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from adhocracy.model.message import Message, message_table
from adhocracy.model.message import MessageRecipient, message_recipient_table
from adhocracy.model.votedetail import votedetail_table
from adhocracy.model.login import Login, login_table


mapper(User, user_table, properties={
Expand Down Expand Up @@ -505,6 +506,12 @@
),
})

mapper(Login, login_table, properties={
'access_time': synonym('_access', map_column=True),
'ip_address': synonym('_ip', map_column=True),
'user': synonym('_user', map_column=True),
'success': synonym('_success', map_column=True)
})

DELETE = "delete"
INSERT = "insert"
Expand Down
52 changes: 52 additions & 0 deletions src/adhocracy/model/login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import hashlib
import os
import logging
import datetime

from babel import Locale
from pylons import config
from pylons.i18n import _

from sqlalchemy import Table, Column
from sqlalchemy import DateTime, Integer, Unicode, UnicodeText

from adhocracy.model import meta
import logging
import meta
from sqlalchemy import MetaData


login_table = Table(
'loginlog', meta.data,
Column('id', Integer, primary_key=True),
Column('access_time', DateTime),
Column('ip_address', Unicode(255), nullable=True),
Column('user', UnicodeText()),
Column('success', UnicodeText())
)


class Login(meta.Indexable):

def __init__(self, access_time, ip_adress, user, success):
self.access_time = datetime.datetime.utcnow()
self.ip_address = ip_adress
self.user = user
self.success = success

# def count returns amount of unsuccessful logins of past hour
@classmethod
def count_logs(cls, user):
q = meta.Session.query(cls)
q = q.filter(cls.user == user, cls.success == 'no',
((datetime.datetime.utcnow()
- datetime.timedelta(hours=1)) < cls.access_time))
return q.count()

@classmethod
def create(cls, access_time, ip_adress, user, success):
l = Login(access_time, ip_adress, user, success)
meta.Session.add(l)
meta.Session.flush()
meta.Session.commit()
return l
5 changes: 4 additions & 1 deletion src/adhocracy/model/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from sqlalchemy import Boolean, DateTime, Integer, Unicode, UnicodeText
from sqlalchemy.orm import eagerload_all

from adhocracy.model import meta
from adhocracy.model import meta, login
from adhocracy.model import instance_filter as ifilter
from adhocracy.model.core import JSONEncodedDict
from adhocracy.model.core import MutationDict
Expand Down Expand Up @@ -236,6 +236,9 @@ def validate_password(self, password):
:return: Whether the password is valid.
:rtype: bool
"""
# user_log = login.Login.create(datetime.utcnow(),
# 123, u'einUser', u'yes')
0
if self.password is None:
return False
if isinstance(password, unicode):
Expand Down