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.i18n import I18n
|
||||||
from paramecio.libraries.sessionplugin import get_session
|
from paramecio.libraries.sessionplugin import get_session
|
||||||
from paramecio.libraries.keyutils import create_key_encrypt
|
from paramecio.libraries.keyutils import create_key_encrypt
|
||||||
from bottle import request
|
from bottle import request, abort
|
||||||
|
|
||||||
# Need unittest
|
# Need unittest
|
||||||
|
|
||||||
|
|
@ -144,3 +144,13 @@ def request_type():
|
||||||
|
|
||||||
return request.environ['REQUEST_METHOD']
|
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.httputils import GetPostFiles
|
||||||
from paramecio.libraries.db.formsutils import check_form, csrf_token
|
from paramecio.libraries.db.formsutils import check_form, csrf_token
|
||||||
from paramecio.libraries.db.coreforms import PasswordForm
|
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=Bottle()
|
||||||
admin_app.install(SessionPlugin())
|
admin_app.install(SessionPlugin())
|
||||||
|
|
@ -138,6 +140,7 @@ def check_login_admin(session={}):
|
||||||
username=getpost.post.get('username')
|
username=getpost.post.get('username')
|
||||||
password=getpost.post.get('password')
|
password=getpost.post.get('password')
|
||||||
remember_login=getpost.post.get('remember_login')
|
remember_login=getpost.post.get('remember_login')
|
||||||
|
token_auth=''
|
||||||
|
|
||||||
if username!='' and password!='' and not no_login:
|
if username!='' and password!='' and not no_login:
|
||||||
|
|
||||||
|
|
@ -162,7 +165,20 @@ def check_login_admin(session={}):
|
||||||
now_str=now()
|
now_str=now()
|
||||||
date_now=format_local_strtime('YYYY-MM-DD HH:mm:ss', now_str)
|
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['login_admin']=True
|
||||||
session['user_id']=result['id']
|
session['user_id']=result['id']
|
||||||
|
|
@ -264,6 +280,59 @@ def change_theme(session={}):
|
||||||
|
|
||||||
return {'error': error, 'message': ''}
|
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):
|
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.modules.admin2.libraries.config import modules_admin, modules_admin_icons
|
||||||
from paramecio.libraries.mtemplates import PTemplate, env_theme
|
from paramecio.libraries.mtemplates import PTemplate, env_theme
|
||||||
from paramecio.libraries.i18n import I18n
|
from paramecio.libraries.i18n import I18n
|
||||||
import paramecio.modules.admin2.libraries.i18n
|
import paramecio.modules.admin2.libraries.i18n as i18n_lang
|
||||||
import os
|
import os
|
||||||
#from paramecio.libraries.lists import SimpleList
|
#from paramecio.libraries.lists import SimpleList
|
||||||
from paramecio.libraries.generate_admin_class import GenerateAdminClass
|
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.wsgiapp import app
|
||||||
from paramecio.libraries.db.webmodel import WebModel
|
from paramecio.libraries.db.webmodel import WebModel
|
||||||
from paramecio.modules.admin2.models.admin import UserAdmin2
|
from paramecio.modules.admin2.models.admin import UserAdmin2
|
||||||
|
from paramecio.libraries.urls import add_get_parameters
|
||||||
|
|
||||||
env=env_theme(__file__)
|
env=env_theme(__file__)
|
||||||
|
|
||||||
t=PTemplate(env)
|
t=PTemplate(env)
|
||||||
|
|
||||||
|
i18n=I18n('admin2')
|
||||||
|
|
||||||
#t.env.directories=admin_t.env.directories
|
#t.env.directories=admin_t.env.directories
|
||||||
"""
|
"""
|
||||||
tpl_path=os.path.dirname(__file__).replace('/admin', '')+'/templates/admin'
|
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.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['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
|
user_admin.fields['password'].protected=False
|
||||||
|
|
||||||
|
|
@ -61,7 +68,9 @@ def admin_users(session={}):
|
||||||
|
|
||||||
admin.list.search_fields=['username']
|
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()
|
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)
|
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 '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)
|
result = callback(*args, **kwargs)
|
||||||
|
|
||||||
return result
|
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'))
|
redirect(app.get_url('admin_app.login_admin'))
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,9 @@ class UserAdmin2(UserModel):
|
||||||
|
|
||||||
self.register(corefields.CharField('token_login'))
|
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'))
|
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