perbaikan validasi login untuk mencegah percobaan login berlebihan

1 parent febbaac4
...@@ -19,10 +19,13 @@ Perubahan Mendasar dari fungsi login adalah: ...@@ -19,10 +19,13 @@ Perubahan Mendasar dari fungsi login adalah:
result object dari fungsi tersebut harus berupa class User() result object dari fungsi tersebut harus berupa class User()
""" """
from operator import ge
from google.oauth2 import id_token
from google.auth.transport import requests
import os import os
from random import Random from random import Random
import re import re
from datetime import timedelta, datetime from datetime import date, timedelta, datetime
from importlib import import_module from importlib import import_module
from pyramid.request import Response from pyramid.request import Response
...@@ -42,7 +45,7 @@ from . import one_hour, two_minutes ...@@ -42,7 +45,7 @@ from . import one_hour, two_minutes
from ..models.users import User, ExternalIdentity from ..models.users import User, ExternalIdentity
from ..models import Partner from ..models import Partner
# , Partner # , Partner
from opensipkd.tools import create_now, set_user_log, get_settings from opensipkd.tools import create_now, set_user_log, get_settings, dmyhms
from opensipkd.tools.buttons import btn_cancel from opensipkd.tools.buttons import btn_cancel
# from .. import get_urls # from .. import get_urls
from .base_views import CSRFSchema, BaseView from .base_views import CSRFSchema, BaseView
...@@ -77,7 +80,18 @@ class Login(CSRFSchema): ...@@ -77,7 +80,18 @@ class Login(CSRFSchema):
# http://deformdemo.repoze.org/interfield/ # http://deformdemo.repoze.org/interfield/
def login_validator(form, value): def login_validator(form, value):
pass exc = colander.Invalid(form, 'Terlalu banyak percobaan')
request = form.request
if request.session.get("login_failed", 0) > 3:
# message = "Login Gagal, terlalu banyak percobaan"
login_blocked = request.session.ses["login_blocked"]
if login_blocked and login_blocked > datetime.now():
exc = colander.Invalid(
form,
'Login Gagal, terlalu banyak percobaan, silahkan coba lagi setelah {}'
.format(dmyhms(login_blocked))
)
raise exc
def get_login_headers(request, user): def get_login_headers(request, user):
...@@ -98,14 +112,25 @@ class LoginUser(object): ...@@ -98,14 +112,25 @@ class LoginUser(object):
# self.identity=identity # self.identity=identity
self.message = "Sukses Login" self.message = "Sukses Login"
self.user = None self.user = None
self.ses = request.session
self.ses["login_failed"] = self.ses.get("login_failed", 0)
self.ses["login_blocked"] = self.ses.get("login_blocked")
def login(self, values, user=None): def login(self, values, user=None):
settings = get_settings()
self.user = user and user or User.get_by_identity(values["username"]) self.user = user and user or User.get_by_identity(values["username"])
if not self.user or not UserService.check_password( if not self.user or not UserService.check_password(
self.user, values["password"]): self.user, values["password"]):
self.message = "Login Gagal" self.message = "Login Gagal"
set_user_log(self.message, self.request, log, values["username"]) set_user_log(self.message, self.request, log, values["username"])
self.ses["login_failed"] += self.ses.get("login_failed", 0) + 1
if self.ses["login_failed"] > 3:
self.ses["login_blocked"] = datetime.now() + \
timedelta(minutes=settings.get("login_blocked_minutes", 1))
return return
self.ses["login_failed"] = 0
self.ses["login_blocked"] = None
for g in self.user.groups: for g in self.user.groups:
log.debug(f"Group: {g.id} as {g.group_name}") log.debug(f"Group: {g.id} as {g.group_name}")
...@@ -123,8 +148,6 @@ class Oauth2ParseExc(Exception): ...@@ -123,8 +148,6 @@ class Oauth2ParseExc(Exception):
class Oauth2UserExc(Exception): class Oauth2UserExc(Exception):
"""Error User Found""" """Error User Found"""
from google.oauth2 import id_token
from google.auth.transport import requests
def verify_android_token(token, web_client_id): def verify_android_token(token, web_client_id):
""" """
...@@ -172,7 +195,8 @@ def verify_android_token(token, web_client_id): ...@@ -172,7 +195,8 @@ def verify_android_token(token, web_client_id):
def oauth2_login(request, params=None): def oauth2_login(request, params=None):
provider_name = params and params["provider_name"] or request.params["provider_name"] provider_name = params and params["provider_name"] or request.params["provider_name"]
if provider_name == "google": if provider_name == "google":
client_platform = params and params.get("platform") or request.params.get("platform") or "web" client_platform = params and params.get(
"platform") or request.params.get("platform") or "web"
web_client_id = request.google_signin_client_id web_client_id = request.google_signin_client_id
if client_platform == "android": if client_platform == "android":
id_info = verify_android_token( id_info = verify_android_token(
...@@ -267,7 +291,7 @@ class ViewAuth(BaseView): ...@@ -267,7 +291,7 @@ class ViewAuth(BaseView):
buttons += (Button('register', _('Register')),) buttons += (Button('register', _('Register')),)
buttons += (Button('reset', _('Reset')), btn_cancel,) buttons += (Button('reset', _('Reset')), btn_cancel,)
form = Form(schema, buttons=buttons) form = Form(schema, buttons=buttons, validator=login_validator)
message = "" message = ""
if 'cancel' in request.POST: if 'cancel' in request.POST:
return HTTPFound(location=request.home) return HTTPFound(location=request.home)
...@@ -315,7 +339,7 @@ class ViewAuth(BaseView): ...@@ -315,7 +339,7 @@ class ViewAuth(BaseView):
if self.req.is_xhr: if self.req.is_xhr:
return Response(json={"error": {"code": -1, return Response(json={"error": {"code": -1,
"msg": login.message}, "msg": login.message},
"data":[]}) "data": []})
next_url = f"{request.route_url('base-login')}?next={next_url}" next_url = f"{request.route_url('base-login')}?next={next_url}"
return HTTPFound(location=next_url) return HTTPFound(location=next_url)
...@@ -420,6 +444,7 @@ class ViewAuth(BaseView): ...@@ -420,6 +444,7 @@ class ViewAuth(BaseView):
return dict(form=form.render()) return dict(form=form.render())
def xhr_response(user, headers): def xhr_response(user, headers):
partner = Partner.query_email(user.email).first() partner = Partner.query_email(user.email).first()
mobile = partner and partner.mobile or "" mobile = partner and partner.mobile or ""
...@@ -439,6 +464,7 @@ def xhr_response(user, headers): ...@@ -439,6 +464,7 @@ def xhr_response(user, headers):
} }
return Response(json=data, headerlist=headers) return Response(json=data, headerlist=headers)
def redirect_login(request, user): def redirect_login(request, user):
set_user_log("Login Sukses", request, log, user.user_name) set_user_log("Login Sukses", request, log, user.user_name)
for g in user.groups: for g in user.groups:
...@@ -638,6 +664,7 @@ class ViewPassword(BaseView): ...@@ -638,6 +664,7 @@ class ViewPassword(BaseView):
sending_mail(self.req, user, subject, body) sending_mail(self.req, user, subject, body)
return dict(data={"message": "Passcode sudah dikirim ke email Anda"}) return dict(data={"message": "Passcode sudah dikirim ke email Anda"})
class ChangePasswordRequest(colander.Schema): class ChangePasswordRequest(colander.Schema):
new_password = colander.SchemaNode( new_password = colander.SchemaNode(
colander.String(), widget=widget.CheckedPasswordWidget()) colander.String(), widget=widget.CheckedPasswordWidget())
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!