Option to log login failures to file

merge-requests/30/head
Bob Mottram 2021-06-09 16:19:30 +01:00
parent 685ed0c22e
commit 1929f97bf4
4 changed files with 50 additions and 13 deletions

22
auth.py
View File

@ -11,6 +11,7 @@ import hashlib
import binascii
import os
import secrets
import datetime
from utils import isSystemAccount
from utils import hasUsersPath
@ -206,7 +207,9 @@ def createPassword(length=10):
return ''.join((secrets.choice(validChars) for i in range(length)))
def recordLoginFailure(ipAddress: str, countDict: {}, failTime: int) -> None:
def recordLoginFailure(baseDir: str, ipAddress: str,
countDict: {}, failTime: int,
logToFile: bool) -> None:
"""Keeps ip addresses and the number of times login failures
occured for them in a dict
"""
@ -226,8 +229,23 @@ def recordLoginFailure(ipAddress: str, countDict: {}, failTime: int) -> None:
}
else:
countDict[ipAddress]['count'] += 1
countDict[ipAddress]['time'] = failTime
failCount = countDict[ipAddress]['count']
if failCount > 4:
print('WARN: ' + str(ipAddress) + ' failed to log in ' +
str(failCount) + ' times')
countDict[ipAddress]['time'] = failTime
if not logToFile:
return
failureLog = baseDir + '/accounts/loginfailures.log'
writeType = 'a+'
if not os.path.isfile(failureLog):
writeType = 'w+'
currTime = datetime.datetime.utcnow()
try:
with open(failureLog, writeType) as fp:
fp.write(currTime.strftime("%Y-%m-%d %H:%M:%SZ") +
' ' + ipAddress + '\n')
except BaseException:
pass

View File

@ -1443,8 +1443,9 @@ class PubServer(BaseHTTPRequestHandler):
ipAddress = self.headers['X-Forwarded-For']
else:
ipAddress = self.client_address[0]
if not isLocalNetworkAddress(ipAddress):
print('Login attempt from IP: ' + str(ipAddress))
if not domain.endswith('.onion'):
if not isLocalNetworkAddress(ipAddress):
print('Login attempt from IP: ' + str(ipAddress))
if not authorizeBasic(baseDir, '/users/' +
loginNickname + '/outbox',
authHeader, False):
@ -1452,10 +1453,12 @@ class PubServer(BaseHTTPRequestHandler):
self._clearLoginDetails(loginNickname, callingDomain)
failTime = int(time.time())
self.server.lastLoginFailure = failTime
if not isLocalNetworkAddress(ipAddress):
recordLoginFailure(ipAddress,
self.server.loginFailureCount,
failTime)
if not domain.endswith('.onion'):
if not isLocalNetworkAddress(ipAddress):
recordLoginFailure(baseDir, ipAddress,
self.server.loginFailureCount,
failTime,
self.server.logLoginFailures)
self.server.POSTbusy = False
return
else:
@ -14844,7 +14847,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
break
def runDaemon(city: str,
def runDaemon(logLoginFailures: bool,
city: str,
showNodeInfoAccounts: bool,
showNodeInfoVersion: bool,
brochMode: bool,
@ -15113,6 +15117,7 @@ def runDaemon(city: str,
httpd.lastLoginTime = 0
httpd.lastLoginFailure = 0
httpd.loginFailureCount = {}
httpd.logLoginFailures = logLoginFailures
httpd.maxReplies = maxReplies
httpd.tokens = {}
httpd.tokensLookup = {}

View File

@ -291,6 +291,11 @@ parser.add_argument("--iconsAsButtons",
type=str2bool, nargs='?',
const=True, default=False,
help="Show header icons as buttons")
parser.add_argument("--logLoginFailures",
dest='logLoginFailures',
type=str2bool, nargs='?',
const=True, default=False,
help="Whether to log longin failures")
parser.add_argument("--rssIconAtTop",
dest='rssIconAtTop',
type=str2bool, nargs='?',
@ -2510,6 +2515,11 @@ brochMode = \
if brochMode is not None:
args.brochMode = bool(brochMode)
logLoginFailures = \
getConfigParam(baseDir, 'logLoginFailures')
if logLoginFailures is not None:
args.logLoginFailures = bool(logLoginFailures)
showNodeInfoAccounts = \
getConfigParam(baseDir, 'showNodeInfoAccounts')
if showNodeInfoAccounts is not None:
@ -2539,7 +2549,8 @@ if setTheme(baseDir, themeName, domain,
print('Theme set to ' + themeName)
if __name__ == "__main__":
runDaemon(args.city,
runDaemon(args.logLoginFailures,
args.city,
args.showNodeInfoAccounts,
args.showNodeInfoVersion,
args.brochMode,

View File

@ -518,8 +518,9 @@ def createServerAlice(path: str, domain: str, port: int,
showNodeInfoAccounts = True
showNodeInfoVersion = True
city = 'London, England'
logLoginFailures = False
print('Server running: Alice')
runDaemon(city,
runDaemon(logLoginFailures, city,
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,
@ -620,8 +621,9 @@ def createServerBob(path: str, domain: str, port: int,
showNodeInfoAccounts = True
showNodeInfoVersion = True
city = 'London, England'
logLoginFailures = False
print('Server running: Bob')
runDaemon(city,
runDaemon(logLoginFailures, city,
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,
@ -677,8 +679,9 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
showNodeInfoAccounts = True
showNodeInfoVersion = True
city = 'London, England'
logLoginFailures = False
print('Server running: Eve')
runDaemon(city,
runDaemon(logLoginFailures, city,
showNodeInfoAccounts,
showNodeInfoVersion,
brochMode,