def test_verify_login_record_is_updated(monkeypatch): monkeypatch.setitem(d.web.ctx, 'weasyl_session', Bag()) user_id = db_utils.create_user() d.engine.execute("UPDATE login SET last_login = -1 WHERE userid = %(id)s", id=user_id) login.signin(user_id) last_login = d.engine.scalar("SELECT last_login FROM login WHERE userid = %(id)s", id=user_id) assert last_login > -1
def test_verify_login_record_is_updated(): # Use a fake session for this test. get_current_request().weasyl_session = Bag() user_id = db_utils.create_user() d.engine.execute("UPDATE login SET last_login = -1 WHERE userid = %(id)s", id=user_id) login.signin(user_id) last_login = d.engine.scalar("SELECT last_login FROM login WHERE userid = %(id)s", id=user_id) assert last_login > -1
def signin_2fa_auth_post_(request): sess = define.get_weasyl_session() # Only render page if the password has been authenticated (we have a UserID stored in the session) if '2fa_pwd_auth_userid' not in sess.additional_data: return Response(define.errorpage(request.userid, errorcode.permission)) tfa_userid = sess.additional_data['2fa_pwd_auth_userid'] session_life = arrow.now( ).timestamp - sess.additional_data['2fa_pwd_auth_timestamp'] if session_life > 300: # Maximum secondary authentication time: 5 minutes _cleanup_2fa_session() return Response( define.errorpage( request.userid, errorcode. error_messages['TwoFactorAuthenticationAuthenticationTimeout'], [["Sign In", "/signin"], ["Return to the Home Page", "/"]])) elif two_factor_auth.verify(tfa_userid, request.params["tfaresponse"]): # 2FA passed, so login and cleanup. _cleanup_2fa_session() login.signin(tfa_userid) ref = request.params["referer"] or "/" # User is out of recovery codes, so force-deactivate 2FA if two_factor_auth.get_number_of_recovery_codes(tfa_userid) == 0: two_factor_auth.force_deactivate(tfa_userid) return Response( define.errorpage( tfa_userid, errorcode.error_messages[ 'TwoFactorAuthenticationZeroRecoveryCodesRemaining'], [["2FA Dashboard", "/control/2fa/status"], ["Return to the Home Page", "/"]])) # Return to the target page, restricting to the path portion of 'ref' per urlparse. raise HTTPSeeOther(location=urlparse.urlparse(ref).path) elif sess.additional_data['2fa_pwd_auth_attempts'] >= 5: # Hinder brute-forcing the 2FA token or recovery code by enforcing an upper-bound on 2FA auth attempts. _cleanup_2fa_session() return Response( define.errorpage( request.userid, errorcode.error_messages[ 'TwoFactorAuthenticationAuthenticationAttemptsExceeded'], [["Sign In", "/signin"], ["Return to the Home Page", "/"]])) else: # Log the failed authentication attempt to the session and save sess.additional_data['2fa_pwd_auth_attempts'] += 1 sess.save = True # 2FA failed; redirect to 2FA input page & inform user that authentication failed. return Response( define.webpage( request.userid, "etc/signin_2fa_auth.html", [ define.get_display_name(tfa_userid), request.params["referer"], two_factor_auth.get_number_of_recovery_codes(tfa_userid), "2fa" ], title="Sign In - 2FA"))
def test_verify_login_record_is_updated(): # Use a fake session for this test. get_current_request().weasyl_session = Bag() user_id = db_utils.create_user() d.engine.execute("UPDATE login SET last_login = -1 WHERE userid = %(id)s", id=user_id) login.signin(user_id) last_login = d.engine.scalar( "SELECT last_login FROM login WHERE userid = %(id)s", id=user_id) assert last_login > -1
def test_verify_login_record_is_updated(): # Use a fake session for this test. user_id = db_utils.create_user() sess = get_current_request().weasyl_session = create_session(user_id) db = d.connect() db.add(sess) db.flush() time = datetime(2020, 1, 1, 00, 00, 1, tzinfo=pytz.UTC) # Arbitrary date that should be earlier than now. d.engine.execute("UPDATE login SET last_login = %(timestamp)s WHERE userid = %(id)s", id=user_id, timestamp=time) login.signin(get_current_request(), user_id) last_login = d.engine.scalar("SELECT last_login FROM login WHERE userid = %(id)s", id=user_id) assert last_login > time
def signin_2fa_auth_post_(request): sess = define.get_weasyl_session() # Only render page if the session exists //and// the password has # been authenticated (we have a UserID stored in the session) if not sess.additional_data or '2fa_pwd_auth_userid' not in sess.additional_data: return Response(define.errorpage(request.userid, errorcode.permission)) tfa_userid = sess.additional_data['2fa_pwd_auth_userid'] session_life = arrow.now().timestamp - sess.additional_data['2fa_pwd_auth_timestamp'] if session_life > 300: # Maximum secondary authentication time: 5 minutes _cleanup_2fa_session() return Response(define.errorpage( request.userid, errorcode.error_messages['TwoFactorAuthenticationAuthenticationTimeout'], [["Sign In", "/signin"], ["Return to the Home Page", "/"]] )) elif two_factor_auth.verify(tfa_userid, request.params["tfaresponse"]): # 2FA passed, so login and cleanup. _cleanup_2fa_session() login.signin(request, tfa_userid, ip_address=request.client_addr, user_agent=request.user_agent) ref = request.params["referer"] or "/" # User is out of recovery codes, so force-deactivate 2FA if two_factor_auth.get_number_of_recovery_codes(tfa_userid) == 0: two_factor_auth.force_deactivate(tfa_userid) return Response(define.errorpage( tfa_userid, errorcode.error_messages['TwoFactorAuthenticationZeroRecoveryCodesRemaining'], [["2FA Dashboard", "/control/2fa/status"], ["Return to the Home Page", "/"]] )) # Return to the target page, restricting to the path portion of 'ref' per urlparse. raise HTTPSeeOther(location=urlparse.urlparse(ref).path) elif sess.additional_data['2fa_pwd_auth_attempts'] >= 5: # Hinder brute-forcing the 2FA token or recovery code by enforcing an upper-bound on 2FA auth attempts. _cleanup_2fa_session() return Response(define.errorpage( request.userid, errorcode.error_messages['TwoFactorAuthenticationAuthenticationAttemptsExceeded'], [["Sign In", "/signin"], ["Return to the Home Page", "/"]] )) else: # Log the failed authentication attempt to the session and save sess.additional_data['2fa_pwd_auth_attempts'] += 1 sess.save = True # 2FA failed; redirect to 2FA input page & inform user that authentication failed. return Response(define.webpage( request.userid, "etc/signin_2fa_auth.html", [define.get_display_name(tfa_userid), request.params["referer"], two_factor_auth.get_number_of_recovery_codes(tfa_userid), "2fa"], title="Sign In - 2FA"))