Fixes in user login
This commit is contained in:
parent
d6fc5b0c4b
commit
5066f5320c
7 changed files with 319 additions and 9 deletions
|
|
@ -5,7 +5,7 @@ from paramecio.libraries.db.coreforms import PasswordForm
|
|||
from paramecio.libraries.i18n import I18n
|
||||
from paramecio.libraries.sessionplugin import get_session
|
||||
from paramecio.libraries.keyutils import create_key_encrypt
|
||||
from bottle import request
|
||||
from bottle import request, abort
|
||||
|
||||
# Need unittest
|
||||
|
||||
|
|
@ -144,3 +144,13 @@ def request_type():
|
|||
|
||||
return request.environ['REQUEST_METHOD']
|
||||
|
||||
def check_csrf(name_csrf_token='csrf_token'):
|
||||
|
||||
session=get_session()
|
||||
|
||||
csrf_token=session.get('csrf_token', '')
|
||||
|
||||
if csrf_token=='' or csrf_token!=request.forms.get(name_csrf_token):
|
||||
abort(403)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ from paramecio.libraries.sessionplugin import SessionPlugin
|
|||
from paramecio.libraries.httputils import GetPostFiles
|
||||
from paramecio.libraries.db.formsutils import check_form, csrf_token
|
||||
from paramecio.libraries.db.coreforms import PasswordForm
|
||||
from paramecio.libraries.sendmail import SendMail
|
||||
from paramecio.libraries.db.formsutils import check_csrf
|
||||
|
||||
admin_app=Bottle()
|
||||
admin_app.install(SessionPlugin())
|
||||
|
|
@ -138,6 +140,7 @@ def check_login_admin(session={}):
|
|||
username=getpost.post.get('username')
|
||||
password=getpost.post.get('password')
|
||||
remember_login=getpost.post.get('remember_login')
|
||||
token_auth=''
|
||||
|
||||
if username!='' and password!='' and not no_login:
|
||||
|
||||
|
|
@ -162,7 +165,20 @@ def check_login_admin(session={}):
|
|||
now_str=now()
|
||||
date_now=format_local_strtime('YYYY-MM-DD HH:mm:ss', now_str)
|
||||
|
||||
db.query('update useradmin2 set token_login=%s, last_login=%s WHERE id=%s', [remember_key, date_now, result['id']])
|
||||
token_auth=''
|
||||
|
||||
if result['double_auth']:
|
||||
|
||||
token_auth=create_key(8)
|
||||
session['verify_auth']=True
|
||||
|
||||
# Send email
|
||||
|
||||
sendmail=SendMail(ssl=True)
|
||||
|
||||
sendmail.send(config.portal_email, [result['email']], i18n.tlang('Code for complete login'), i18n.tlang('We send to you a code for activate your account using double authentication:')+"\n"+token_auth, content_type='plain', attachments=[])
|
||||
|
||||
db.query('update useradmin2 set token_login=%s, last_login=%s, token_auth=%s WHERE id=%s', [remember_key, date_now, usermodel.fields['password'].check(token_auth), result['id']])
|
||||
|
||||
session['login_admin']=True
|
||||
session['user_id']=result['id']
|
||||
|
|
@ -264,6 +280,59 @@ def change_theme(session={}):
|
|||
|
||||
return {'error': error, 'message': ''}
|
||||
|
||||
@admin_app.get('/need_auth', skip=[check_login], name='admin_app.need_auth')
|
||||
def need_auth(session={}):
|
||||
|
||||
i18n=I18n('admin2')
|
||||
|
||||
return t.load_template('need_auth.phtml', title=i18n.tlang('Auth check'))
|
||||
|
||||
@admin_app.post('/auth_check', skip=[check_login], name='admin_app.auth_check')
|
||||
def auth_check(session={}):
|
||||
|
||||
error=1
|
||||
|
||||
#check_csrf()
|
||||
|
||||
you_cannot_login=0
|
||||
|
||||
db=WebModel.connection()
|
||||
|
||||
if 'login_admin' in session:
|
||||
|
||||
code=request.forms.get('code', '')
|
||||
|
||||
user_admin=UserAdmin2(db)
|
||||
|
||||
user_admin.check_user=False
|
||||
|
||||
arr_user=user_admin.set_conditions('WHERE id=%s', [session.get('user_id', 0)]).select_a_row_where()
|
||||
#print(arr_user)
|
||||
if arr_user:
|
||||
|
||||
if user_admin.fields['token_auth'].verify(code, arr_user['token_auth']):
|
||||
|
||||
user_admin.safe_query()
|
||||
|
||||
#user_admin.set_conditions('WHERE id=%s', [session['user_id']]).update({'token_auth': ''})
|
||||
user_admin.query('update useradmin2 set token_auth="" WHERE id=%s', [session['user_id']])
|
||||
|
||||
session['verify_auth']=False
|
||||
error=0
|
||||
|
||||
else:
|
||||
|
||||
#you_cannot_login=check_login_tries()
|
||||
you_cannot_login=check_login_tries(request, db)
|
||||
|
||||
else:
|
||||
|
||||
you_cannot_login=check_login_tries()
|
||||
|
||||
db.close()
|
||||
|
||||
return {'error': error, 'you_cannot_login': you_cannot_login}
|
||||
|
||||
|
||||
def check_login_tries(request, db):
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from paramecio.modules.admin2.app import admin_app
|
|||
from paramecio.modules.admin2.libraries.config import modules_admin, modules_admin_icons
|
||||
from paramecio.libraries.mtemplates import PTemplate, env_theme
|
||||
from paramecio.libraries.i18n import I18n
|
||||
import paramecio.modules.admin2.libraries.i18n
|
||||
import paramecio.modules.admin2.libraries.i18n as i18n_lang
|
||||
import os
|
||||
#from paramecio.libraries.lists import SimpleList
|
||||
from paramecio.libraries.generate_admin_class import GenerateAdminClass
|
||||
|
|
@ -13,11 +13,14 @@ from paramecio.libraries.db.coreforms import PasswordForm
|
|||
from paramecio.wsgiapp import app
|
||||
from paramecio.libraries.db.webmodel import WebModel
|
||||
from paramecio.modules.admin2.models.admin import UserAdmin2
|
||||
from paramecio.libraries.urls import add_get_parameters
|
||||
|
||||
env=env_theme(__file__)
|
||||
|
||||
t=PTemplate(env)
|
||||
|
||||
i18n=I18n('admin2')
|
||||
|
||||
#t.env.directories=admin_t.env.directories
|
||||
"""
|
||||
tpl_path=os.path.dirname(__file__).replace('/admin', '')+'/templates/admin'
|
||||
|
|
@ -45,11 +48,15 @@ def admin_users(session={}):
|
|||
|
||||
user_admin.fields['dark_theme'].name_form=SelectForm
|
||||
|
||||
user_admin.create_forms(['username', 'password', 'email', 'privileges', 'lang', 'dark_theme'])
|
||||
user_admin.fields['double_auth'].name_form=SelectForm
|
||||
|
||||
user_admin.create_forms(['username', 'password', 'email', 'privileges', 'lang', 'dark_theme', 'double_auth'])
|
||||
|
||||
user_admin.forms['privileges'].arr_select={0: I18n.lang('admin', 'without_privileges', 'Without privileges'), 1: I18n.lang('admin', 'selected_privileges', 'Selected privileges'), 2: I18n.lang('admin', 'administrator', 'Administrator')}
|
||||
|
||||
user_admin.forms['dark_theme'].arr_select={0: _('Light theme'), 1: _('Dark theme')}
|
||||
user_admin.forms['dark_theme'].arr_select={0: i18n.tlang('Light theme'), 1: i18n.tlang('Dark theme')}
|
||||
|
||||
user_admin.forms['double_auth'].arr_select={0: i18n.tlang('No'), 1: i18n.tlang('Yes')}
|
||||
|
||||
user_admin.fields['password'].protected=False
|
||||
|
||||
|
|
@ -61,7 +68,9 @@ def admin_users(session={}):
|
|||
|
||||
admin.list.search_fields=['username']
|
||||
|
||||
admin.arr_fields_edit=['username', 'password', 'repeat_password', 'email', 'privileges', 'lang', 'dark_theme']
|
||||
admin.arr_fields_edit=['username', 'password', 'repeat_password', 'email', 'privileges', 'lang', 'dark_theme', 'double_auth']
|
||||
|
||||
admin.list.arr_extra_options=[user_options]
|
||||
|
||||
slist=admin.show()
|
||||
|
||||
|
|
@ -69,4 +78,20 @@ def admin_users(session={}):
|
|||
|
||||
return t.load_template('users.phtml', title=i18n.tlang('Admin users'), tlang=i18n.tlang, module_selected='admin_app.admin_users', slist=slist, session=session)
|
||||
|
||||
@admin_app.get('/ausers/permissions/<user_id:int>', name="admin_app.admin_permissions")
|
||||
def admin_users(user_id, session={}):
|
||||
|
||||
db=WebModel.connection()
|
||||
|
||||
db.close()
|
||||
|
||||
return ""
|
||||
|
||||
def user_options(url, id, arr_row):
|
||||
|
||||
options=[]
|
||||
options.append('<a href="'+add_get_parameters(url, op_admin=1, id=id)+'">'+I18n.lang('common', 'edit', 'Edit')+'</a>')
|
||||
if not arr_row['privileges']:
|
||||
options.append(f'<a href="{app.get_url('admin_app.admin_permissions', user_id=id)}">'+i18n.tlang('User access')+'</a>')
|
||||
options.append('<a href="'+add_get_parameters(url, op_admin=3, id=id)+'">'+I18n.lang('common', 'delete', 'Delete')+'</a>')
|
||||
return options
|
||||
|
|
|
|||
|
|
@ -8,12 +8,15 @@ def check_login(callback):
|
|||
|
||||
if 'session' in request.environ:
|
||||
|
||||
if request.environ['session'].get('login_admin', 0):
|
||||
if request.environ['session'].get('login_admin', False) and not request.environ['session'].get('verify_auth', False):
|
||||
|
||||
result = callback(*args, **kwargs)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if request.environ['session'].get('verify_auth', False):
|
||||
redirect(app.get_url('admin_app.need_auth'))
|
||||
|
||||
redirect(app.get_url('admin_app.login_admin'))
|
||||
|
||||
return wrapper
|
||||
|
|
|
|||
|
|
@ -49,7 +49,9 @@ class UserAdmin2(UserModel):
|
|||
|
||||
self.register(corefields.CharField('token_login'))
|
||||
|
||||
#self.register(PasswordField('token_auth'))
|
||||
self.register(PasswordField('token_auth'))
|
||||
|
||||
self.register(PasswordField('token_key'))
|
||||
|
||||
self.register(PrivilegesField2('privileges'))
|
||||
|
||||
|
|
|
|||
4
paramecio/modules/admin2/templates/access.phtml
Normal file
4
paramecio/modules/admin2/templates/access.phtml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<%inherit file="layout.phtml"/>
|
||||
<%block name="content">
|
||||
|
||||
</%block>
|
||||
197
paramecio/modules/admin2/templates/need_auth.phtml
Normal file
197
paramecio/modules/admin2/templates/need_auth.phtml
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<%inherit file="login.phtml"/>
|
||||
<%block name="content">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary">
|
||||
${tlang('Auth code')}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="#" id="auth_code_form" class="needs-validation" novalidate>
|
||||
<div class="mb-3">
|
||||
<label for="code_form" class="form-label">${tlang('Check your email for get instructions for complete login with double auth or')} <a href="${url_for('admin_app.logout_admin')}">logout</a> and login again with other user</label>
|
||||
<input type="text" class="form-control form-control-lg has-validation" id="code_form" name="code" aria-describedby="code" autocomplete="off" required>
|
||||
<div class="invalid-feedback" id="txt_error_code">
|
||||
${tlang('You need a valid code')}
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" id="code_submit" class="btn btn-primary">${tlang('Check code')}</button>
|
||||
${csrf_token()|n}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<!--<div class="form">
|
||||
<p align="center">${tlang('Check your email for get instructions for complete login with double auth or')} <a href="${url_for('admin_app.logout_admin')}">logout</a> and login again with other user</p>
|
||||
<p><label>${tlang('Code')} *</label><input type="text" class="" name="code" id="code_form" value="" /> <span class="error" id="code_error"></span></p>
|
||||
${csrf_token()|n}
|
||||
</div>
|
||||
<div id="submit_block">
|
||||
<input type="submit" value="${tlang('Send code')}" class="submit" id="code_submit"/>
|
||||
<span id="loading"> </span>
|
||||
</div>-->
|
||||
|
||||
</%block>
|
||||
<%block name="jscript">
|
||||
<script language="javascript">
|
||||
$(document).ready( function () {
|
||||
|
||||
var forms = document.querySelectorAll('.needs-validation');
|
||||
var error=false;
|
||||
|
||||
Array.prototype.slice.call(forms)
|
||||
.forEach(function (form) {
|
||||
form.addEventListener('submit', function (event) {
|
||||
|
||||
error=false;
|
||||
|
||||
/*if (!form.checkValidity()) {
|
||||
|
||||
error=true;
|
||||
|
||||
}*/
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
//form.classList.add('was-validated');
|
||||
|
||||
if(!error) {
|
||||
|
||||
$('#code_submit').prop('disabled', true);
|
||||
|
||||
console.log('Checking done!');
|
||||
|
||||
$('#loading').show();
|
||||
|
||||
data_form={'code': $('#code_form').val(), 'csrf_token': $("#csrf_token").val()};
|
||||
|
||||
$.ajax({
|
||||
url: "${url_for('admin_app.auth_check')}",
|
||||
method: "POST",
|
||||
dataType: "json",
|
||||
data: data_form,
|
||||
error: function(jqXHR, textStatus, errorThrown ) {
|
||||
|
||||
form.classList.add('was-validated');
|
||||
alert(textStatus);
|
||||
$('#code_submit').prop('disabled', false);
|
||||
$('#code_form').get(0).setCustomValidity("${tlang('Error, please try again later')}");
|
||||
|
||||
}
|
||||
}).done(function(data) {
|
||||
|
||||
form.classList.add('was-validated');
|
||||
|
||||
if(data.error==0)
|
||||
{
|
||||
|
||||
//location.reload()
|
||||
location.href="${url_for('admin_app.home_admin')}";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#code_submit').prop('disabled', false);
|
||||
|
||||
// Firefox have a horrible and stupid bug and you need attr for set de new csrf_token
|
||||
|
||||
$('#csrf_token').attr('value', data.csrf_token);
|
||||
|
||||
$('#loading').hide('slow');
|
||||
|
||||
if(data.hasOwnProperty('disable')) {
|
||||
|
||||
//$('#code_error').html("${tlang('Error, your user is disabled, you need support of web administration')}");
|
||||
$('#code_form').get(0).setCustomValidity("${tlang('Error, your user is disabled, you need support of web administration')}");
|
||||
|
||||
$('#txt_error_code').html("${tlang('Error, your user is disabled, you need support of web administration')}");
|
||||
|
||||
} else {
|
||||
$('#code_form').get(0).setCustomValidity("${tlang('Error, wrong code')}");
|
||||
//$('#code_error').html("${tlang('Error, wrong code')}");
|
||||
$('#txt_error_code').html("${tlang('Error, wrong code')}");
|
||||
}
|
||||
|
||||
if(data.you_cannot_login) {
|
||||
|
||||
//$('#code_error').html("${tlang('Error, excessive tries, wait some minutes for login again')}");
|
||||
$('#code_form').get(0).setCustomValidity("${tlang('Error, excessive tries, wait some minutes for login again')}");
|
||||
$('#txt_error_code').html("${tlang('Error, excessive tries, wait some minutes for login again')}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
});
|
||||
|
||||
/*$('#code_submit').click( function () {
|
||||
|
||||
$('#code_submit').prop('disabled', true);
|
||||
|
||||
$('#loading').show();
|
||||
|
||||
data_form={'code': $('#code_form').val(), 'csrf_token': $("#csrf_token").val()};
|
||||
|
||||
$.ajax({
|
||||
url: "",
|
||||
method: "POST",
|
||||
dataType: "json",
|
||||
data: data_form,
|
||||
error: function(jqXHR, textStatus, errorThrown ) {
|
||||
|
||||
alert(textStatus);
|
||||
$('#code_submit').prop('disabled', false);
|
||||
|
||||
}
|
||||
}).done(function(data) {
|
||||
|
||||
if(data.error==0)
|
||||
{
|
||||
|
||||
//location.reload()
|
||||
location.href="";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#code_submit').prop('disabled', false);
|
||||
|
||||
// Firefox have a horrible and stupid bug and you need attr for set de new csrf_token
|
||||
|
||||
$('#csrf_token').attr('value', data.csrf_token);
|
||||
|
||||
$('#loading').hide('slow');
|
||||
|
||||
if(data.hasOwnProperty('disable')) {
|
||||
|
||||
$('#code_error').html("${tlang('Error, your user is disabled, you need support of web administration')}");
|
||||
|
||||
} else {
|
||||
|
||||
$('#code_error').html("${tlang('Error, wrong code')}");
|
||||
|
||||
}
|
||||
|
||||
if(data.you_cannot_login) {
|
||||
|
||||
$('#code_error').html("${tlang('Error, excessive tries, wait some minutes for login again')}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return false;
|
||||
|
||||
});
|
||||
*/
|
||||
});
|
||||
</script>
|
||||
</%block>
|
||||
Loading…
Add table
Add a link
Reference in a new issue