..LDAP用户导入功能完成,准备实现导入用户的登录功能。

pull/130/head
Apex Liu 2018-11-06 01:31:54 +08:00
parent 4c14a58877
commit 493e991787
6 changed files with 567 additions and 142 deletions

View File

@ -28,7 +28,7 @@ $app.on_init = function (cb_stack) {
}; };
cb_stack cb_stack
.add($app.test) // .add($app.test)
.add($app.create_controls) .add($app.create_controls)
.add($app.load_role_list); .add($app.load_role_list);
@ -109,7 +109,7 @@ $app.create_controls = function (cb_stack) {
align: 'center', align: 'center',
width: 70, width: 70,
render: 'make_action_btn', render: 'make_action_btn',
fields: {id: 'id', state: 'state'} fields: {id: 'id', state: 'state', user_type: 'type'}
} }
], ],
@ -144,6 +144,7 @@ $app.create_controls = function (cb_stack) {
}); });
$tp.create_table_pagination($app.table_users, 'table-user-list-pagination'); $tp.create_table_pagination($app.table_users, 'table-user-list-pagination');
//------------------------------- //-------------------------------
// 对话框 // 对话框
//------------------------------- //-------------------------------
@ -239,12 +240,19 @@ $app.on_table_users_cell_created = function (tbl, row_id, col_key, cell_obj) {
if (action === 'edit') { if (action === 'edit') {
$app.dlg_edit_user.show_edit(row_id); $app.dlg_edit_user.show_edit(row_id);
} else if (action === 'reset-password') { } else if (action === 'reset-password') {
console.log(user);
if(user.type === TP_USER_TYPE_LDAP)
return;
$app.dlg_reset_password.show_edit(row_id); $app.dlg_reset_password.show_edit(row_id);
} else if (action === 'reset-oath-bind') { } else if (action === 'reset-oath-bind') {
$app._reset_oath_bind(user.id); $app._reset_oath_bind(user.id);
} else if (action === 'lock') { } else if (action === 'lock') {
if (user.state !== TP_STATE_NORMAL)
return;
$app._lock_users([user.id]); $app._lock_users([user.id]);
} else if (action === 'unlock') { } else if (action === 'unlock') {
if (user.state === TP_STATE_NORMAL)
return;
$app._unlock_users([user.id]); $app._unlock_users([user.id]);
} else if (action === 'remove') { } else if (action === 'remove') {
$app._remove_users([user.id]); $app._remove_users([user.id]);
@ -411,7 +419,15 @@ $app.on_table_users_render_created = function (render) {
h.push('<li' + class_unlock + '><a href="javascript:;" data-action="unlock"><i class="fa fa-unlock fa-fw"></i> 解禁</a></li>'); h.push('<li' + class_unlock + '><a href="javascript:;" data-action="unlock"><i class="fa fa-unlock fa-fw"></i> 解禁</a></li>');
h.push('<li role="separator" class="divider"></li>'); h.push('<li role="separator" class="divider"></li>');
h.push('<li><a href="javascript:;" data-action="reset-password"><i class="fa fa-street-view fa-fw"></i> 重置密码</a></li>');
var class_user_type = '';
if (fields.user_type === TP_USER_TYPE_LDAP) {
class_user_type = ' class="disabled"';
} else {
class_user_type = '';
}
h.push('<li' + class_user_type +'><a href="javascript:;" data-action="reset-password"><i class="fa fa-street-view fa-fw"></i> 重置密码</a></li>');
h.push('<li><a href="javascript:;" data-action="reset-oath-bind"><i class="fa fa-street-view fa-fw"></i> 重置身份验证器</a></li>'); h.push('<li><a href="javascript:;" data-action="reset-oath-bind"><i class="fa fa-street-view fa-fw"></i> 重置身份验证器</a></li>');
h.push('<li role="separator" class="divider"></li>'); h.push('<li role="separator" class="divider"></li>');
h.push('<li><a href="javascript:;" data-action="remove"><i class="fa fa-times-circle fa-fw"></i> 删除</a></li>'); h.push('<li><a href="javascript:;" data-action="remove"><i class="fa fa-times-circle fa-fw"></i> 删除</a></li>');
@ -1436,6 +1452,7 @@ $app.create_dlg_ldap_config = function () {
dlg.dom.btn_save.removeAttr('disabled'); dlg.dom.btn_save.removeAttr('disabled');
if (ret.code === TPE_OK) { if (ret.code === TPE_OK) {
$app.options.sys_cfg.ldap = dlg.ldap_config; $app.options.sys_cfg.ldap = dlg.ldap_config;
dlg.dom.dialog.modal('hide');
$tp.notify_success('保存LDAP设置成功'); $tp.notify_success('保存LDAP设置成功');
} else { } else {
$tp.notify_error('保存LDAP设置失败' + tp_error_msg(ret.code, ret.message)); $tp.notify_error('保存LDAP设置失败' + tp_error_msg(ret.code, ret.message));
@ -1546,32 +1563,172 @@ $app.create_dlg_ldap_import = function () {
dialog: $('#' + dlg.dom_id), dialog: $('#' + dlg.dom_id),
table: $('#table-ldap-import'), table: $('#table-ldap-import'),
chkbox_user_list_select_all: $('#table-ldap-user-select-all'),
btn_refresh: $('#btn-ldap-import-refresh'), btn_refresh: $('#btn-ldap-import-refresh'),
btn_import: $('#btn-ldap-import-import') btn_import: $('#btn-ldap-import-import')
}; };
dlg.init = function (cb_stack) { dlg.init = function (cb_stack) {
dlg.dom.btn_refresh.click(dlg.do_refresh);
//-------------------------------
// LDAP用户列表表格
//-------------------------------
var table_ldap_users_options = {
dom_id: 'table-ldap-user-list',
data_source: {
type: 'none'
},
column_default: {sort: false, align: 'left'},
columns: [
{
// title: '<input type="checkbox" id="user-list-select-all" value="">',
title: '',
key: 'chkbox',
sort: false,
width: 36,
align: 'center',
render: 'make_check_box',
fields: {id: 'id'}
},
{
title: "用户名",
key: "username",
sort: false
},
{
title: "姓名",
key: "surname",
// width: 120,
sort: false
},
{
title: "邮箱",
key: "email",
// width: 120,
sort: false
},
{
title: "状态",
key: "bind",
sort: false,
width: 80,
align: 'center',
render: 'ldap_user_state',
fields: {bind: 'bind'}
}
],
// 重载回调函数
on_render_created: dlg.on_table_users_render_created,
on_cell_created: dlg.on_table_users_cell_created
};
$app.table_ldap_users = $tp.create_table(table_ldap_users_options);
cb_stack
.add($app.table_ldap_users.init);
dlg.dom.btn_refresh.click(function () {
dlg.load_users();
});
dlg.dom.chkbox_user_list_select_all.click(function () {
var _objects = $('#' + $app.table_ldap_users.dom_id + ' tbody').find('[data-check-box]');
if ($(this).is(':checked')) {
$.each(_objects, function (i, _obj) {
$(_obj).prop('checked', true);
});
} else {
$.each(_objects, function (i, _obj) {
$(_obj).prop('checked', false);
});
}
});
// dlg.dom.btn_refresh.click(dlg.load_users);
dlg.dom.btn_import.click(dlg.do_import); dlg.dom.btn_import.click(dlg.do_import);
cb_stack.exec(); cb_stack.exec();
}; };
dlg.show = function () { dlg.get_selected_user = function (tbl) {
dlg.dom.dialog.modal({backdrop: 'static'}); var items = [];
dlg.do_refresh(); var _objs = $('#' + tbl.dom_id + ' tbody tr td input[data-check-box]');
$.each(_objs, function (i, _obj) {
if ($(_obj).is(':checked')) {
var _row_data = tbl.get_row(_obj);
items.push(_row_data.id);
}
});
return items;
}; };
dlg.do_refresh = function () { dlg.on_table_users_cell_created = function (tbl, row_id, col_key, cell_obj) {
if (col_key === 'chkbox') {
cell_obj.find('[data-check-box]').click(function () {
dlg.check_user_list_all_selected();
});
}
};
dlg.on_table_users_render_created = function (render) {
render.make_check_box = function (row_id, fields) {
return '<span><input type="checkbox" data-check-box="' + fields.id + '" data-row-id="' + row_id + '"></span>';
};
render.user_state = function (row_id, fields) {
if (fields.bind) {
return '已导入';
}
};
};
dlg.check_user_list_all_selected = function (cb_stack) {
var _all_checked = true;
var _objs = $('#' + $app.table_ldap_users.dom_id + ' tbody').find('[data-check-box]');
if (_objs.length === 0) {
_all_checked = false;
} else {
$.each(_objs, function (i, _obj) {
if (!$(_obj).is(':checked')) {
_all_checked = false;
return false;
}
});
}
if (_all_checked) {
dlg.dom.chkbox_user_list_select_all.prop('checked', true);
} else {
dlg.dom.chkbox_user_list_select_all.prop('checked', false);
}
if (cb_stack)
cb_stack.exec();
};
dlg.show = function () {
dlg.load_users();
dlg.dom.dialog.modal({backdrop: 'static'});
};
dlg.load_users = function (cb_stack) {
cb_stack = cb_stack || CALLBACK_STACK.create();
dlg.dom.btn_refresh.attr('disabled', 'disabled'); dlg.dom.btn_refresh.attr('disabled', 'disabled');
$tp.ajax_post_json('/system/do-ldap-get-users', { $tp.ajax_post_json('/system/do-ldap-get-users', {},
},
function (ret) { function (ret) {
dlg.dom.btn_refresh.removeAttr('disabled'); dlg.dom.btn_refresh.removeAttr('disabled');
if (ret.code === TPE_OK) { if (ret.code === TPE_OK) {
// $tp.notify_success('列举LDAP用户成功');
console.log(ret.data); console.log(ret.data);
//$app.dlg_ldap_test_result.show(ret.data);
dlg._show_users(ret.data); var _d = [];
for (var i = 0; i < ret.data.length; ++i) {
_d.push(ret.data[i]);
}
cb_stack.add(dlg.check_user_list_all_selected);
$app.table_ldap_users.set_data(cb_stack, {}, {total: ret.data.length, page_index: 1, data: _d});
} else { } else {
$tp.notify_error('获取LDAP用户列表失败' + tp_error_msg(ret.code, ret.message)); $tp.notify_error('获取LDAP用户列表失败' + tp_error_msg(ret.code, ret.message));
} }
@ -1584,60 +1741,34 @@ $app.create_dlg_ldap_import = function () {
); );
}; };
dlg._show_users = function(data) {
dlg.dom.table.empty();
var attr_names = ['username', 'surname', 'email'];
var h = [];
var dn, x;
var th_created = false;
for (dn in data) {
if (!th_created) {
h.push('<thead>');
for (x in attr_names) {
h.push('<th style="text-align:left;" class="mono">');
h.push(attr_names[x]);
h.push('</th>');
}
h.push('</thead>');
th_created = true;
}
h.push('<tr>');
for (x in attr_names) {
h.push('<td style="text-align:left;" class="mono">');
if (!_.isEmpty(data[dn][attr_names[x]]))
h.push(data[dn][attr_names[x]]);
else
h.push('');
h.push('</td>');
}
h.push('</tr>');
}
dlg.dom.table.append($(h.join('')));
dlg.dom.dialog.modal();
};
dlg.do_import = function () { dlg.do_import = function () {
if (!dlg.check_fields()) var items = dlg.get_selected_user($app.table_ldap_users);
if (items.length === 0) {
$tp.notify_error('请选择要导入的账号!');
return; return;
dlg.dom.btn_save.attr('disabled', 'disabled'); }
$tp.ajax_post_json('/system/do-ldap-import', {
}, console.log(items);
dlg.dom.btn_import.attr('disabled', 'disabled');
$tp.ajax_post_json('/system/do-ldap-import', {ldap_users: items},
function (ret) { function (ret) {
dlg.dom.btn_save.removeAttr('disabled'); dlg.dom.btn_import.removeAttr('disabled');
if (ret.code === TPE_OK) { if (ret.code === TPE_OK) {
$app.options.sys_cfg.ldap = dlg.ldap_config; CALLBACK_STACK.create()
$tp.notify_success('保存LDAP设置成功'); .add($app.table_users.load_data)
.add(dlg.check_user_list_all_selected)
.add(dlg.load_users)
.exec();
$tp.notify_success('导入LDAP用户成功');
} else { } else {
$tp.notify_error('保存LDAP设置失败' + tp_error_msg(ret.code, ret.message)); $tp.notify_error('导入LDAP用户失败' + tp_error_msg(ret.code, ret.message));
} }
}, },
function () { function () {
dlg.dom.btn_save.removeAttr('disabled'); dlg.dom.btn_import.removeAttr('disabled');
$tp.notify_error('网络故障,保存LDAP设置失败!'); $tp.notify_error('网络故障导入LDAP用户失败');
}, },
15000 15000
); );

View File

@ -44,33 +44,42 @@
<div class="table-prefix-area"> <div class="table-prefix-area">
<div class="table-extend-cell"> <div class="table-extend-cell">
<span class="table-name"><i class="fa fa-list fa-fw"></i> 用户列表</span> <span class="table-name"><i class="fa fa-list fa-fw"></i> 用户列表</span>
<button id="btn-refresh-user-list" class="btn btn-sm btn-default"><i class="fa fa-redo fa-fw"></i> 刷新列表</button> <button id="btn-refresh-user-list" class="btn btn-sm btn-default"><i class="fa fa-redo fa-fw"></i> 刷新列表
</button>
</div> </div>
<div class="table-extend-cell table-extend-cell-right group-actions"> <div class="table-extend-cell table-extend-cell-right group-actions">
<button id="btn-create-user" class="btn btn-sm btn-primary"><i class="fa fa-plus-circle fa-fw"></i> 创建用户</button> <button id="btn-create-user" class="btn btn-sm btn-primary"><i class="fa fa-plus-circle fa-fw"></i> 创建用户
<button id="btn-import-user" class="btn btn-sm btn-default"><i class="fa fa-plus-square fa-fw"></i> 导入用户</button> </button>
<button id="btn-import-user" class="btn btn-sm btn-default"><i class="fa fa-plus-square fa-fw"></i> 导入用户
</button>
<div class="btn-group btn-group-sm dropdown" id="filter-host-group"> <div class="btn-group btn-group-sm dropdown" id="filter-host-group">
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown"><i class="fas fa-address-book fa-fw"></i> LDAP管理(试验) <i class="fa fa-caret-right"></i></button> <button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown"><i
class="fas fa-address-book fa-fw"></i> LDAP管理(试验) <i class="fa fa-caret-right"></i></button>
<ul class="dropdown-menu dropdown-menu-right dropdown-menu-sm"> <ul class="dropdown-menu dropdown-menu-right dropdown-menu-sm">
<li> <li>
<li><a href="javascript:;" data-action="ldap-import"><i class="fas fa-arrow-alt-circle-left fa-fw"></i> 导入LDAP用户</a></li> <li><a href="javascript:;" data-action="ldap-import"><i
class="fas fa-arrow-alt-circle-left fa-fw"></i> 导入LDAP用户</a></li>
</li> </li>
<li role="separator" class="divider"></li> <li role="separator" class="divider"></li>
<li> <li>
<li><a href="javascript:;" data-action="ldap-config"><i class="fas fa-cog fa-fw"></i> 设置LDAP</a></li> <li><a href="javascript:;" data-action="ldap-config"><i class="fas fa-cog fa-fw"></i> 设置LDAP</a>
</li>
</li> </li>
<li> <li>
<li><a href="javascript:;" data-action="ldap-sync"><i class="fas fa-link fa-fw"></i> 同步LDAP</a></li> <li><a href="javascript:;" data-action="ldap-sync"><i class="fas fa-link fa-fw"></i> 同步LDAP</a>
</li>
</li> </li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
<table id="table-user-list" class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table> <table id="table-user-list"
class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table>
<div class="table-extend-area"> <div class="table-extend-area">
<div class="table-extend-cell checkbox-select-all"><input id="table-user-list-select-all" type="checkbox"/></div> <div class="table-extend-cell checkbox-select-all"><input id="table-user-list-select-all" type="checkbox"/>
</div>
## _ret.push('<div id="' + _tblf.dom_id + '" class="btn-group search-select">'); ## _ret.push('<div id="' + _tblf.dom_id + '" class="btn-group search-select">');
## _ret.push('<button type="button" class="btn dropdown-toggle" data-toggle="dropdown">'); ## _ret.push('<button type="button" class="btn dropdown-toggle" data-toggle="dropdown">');
@ -88,14 +97,20 @@
<div class="table-extend-cell group-actions"> <div class="table-extend-cell group-actions">
<div class="btn-group"> <div class="btn-group">
<div class="btn-group dropup" id="btn-set-role" role="group"> <div class="btn-group dropup" id="btn-set-role" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><i class="fas fa-user fa-fw"></i> 设置角色 <i class="fa fa-caret-right"></i></button> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><i
class="fas fa-user fa-fw"></i> 设置角色 <i class="fa fa-caret-right"></i></button>
<ul class="dropdown-menu dropdown-menu-sm"></ul> <ul class="dropdown-menu dropdown-menu-sm"></ul>
</div> </div>
## <button id="btn-set-role" type="button" class="btn btn-default"><i class="fa fa-edit fa-fw"></i> 设置角色</button> ## <button id="btn-set-role" type="button" class="btn btn-default"><i class="fa fa-edit fa-fw"></i> 设置角色</button>
<button id="btn-lock-user" type="button" class="btn btn-default"><i class="fa fa-lock fa-fw"></i> 禁用</button> <button id="btn-lock-user" type="button" class="btn btn-default"><i class="fa fa-lock fa-fw"></i> 禁用
<button id="btn-unlock-user" type="button" class="btn btn-default"><i class="fa fa-unlock fa-fw"></i> 解禁</button> </button>
<button id="btn-remove-user" type="button" class="btn btn-default"><i class="fa fa-times-circle fa-fw"></i> 删除</button> <button id="btn-unlock-user" type="button" class="btn btn-default"><i
class="fa fa-unlock fa-fw"></i> 解禁
</button>
<button id="btn-remove-user" type="button" class="btn btn-default"><i
class="fa fa-times-circle fa-fw"></i> 删除
</button>
</div> </div>
</div> </div>
<div class="table-extend-cell table-item-counter"> <div class="table-extend-cell table-item-counter">
@ -119,7 +134,9 @@
<p>说明:</p> <p>说明:</p>
<ul class="help-list"> <ul class="help-list">
<li>可以通过表格标题栏进行搜索或过滤,以便快速定位你需要的信息。标题栏左侧的 <i class="fa fa-undo fa-fw"></i> 可以重置过滤器。</li> <li>可以通过表格标题栏进行搜索或过滤,以便快速定位你需要的信息。标题栏左侧的 <i class="fa fa-undo fa-fw"></i> 可以重置过滤器。</li>
<li>批量导入用户需要上传.csv格式的文件您可以 <a href="/static/download/teleport-example-user.csv"><i class="fa fa-download fa-fw"></i>下载用户信息文件模板</a> 进行编辑。</li> <li>批量导入用户需要上传.csv格式的文件您可以 <a href="/static/download/teleport-example-user.csv"><i
class="fa fa-download fa-fw"></i>下载用户信息文件模板</a> 进行编辑。
</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -130,7 +147,8 @@
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 data-field="dlg-title" class="modal-title"></h3> <h3 data-field="dlg-title" class="modal-title"></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -141,8 +159,12 @@
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-sm btn-primary" data-field="btn-edit"><i class="fa fa-edit fa-fw"></i> 编辑用户信息</button> <button type="button" class="btn btn-sm btn-primary" data-field="btn-edit"><i
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-times fa-fw"></i> 关闭</button> class="fa fa-edit fa-fw"></i> 编辑用户信息
</button>
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i
class="fa fa-times fa-fw"></i> 关闭
</button>
</div> </div>
</div> </div>
</div> </div>
@ -152,7 +174,8 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 data-field="dlg-title" class="modal-title"></h3> <h3 data-field="dlg-title" class="modal-title"></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -169,7 +192,8 @@
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<label for="edit-user-username" class="col-sm-2 control-label require">账号:</label> <label for="edit-user-username" class="col-sm-2 control-label require">账号:</label>
<div class="col-sm-5"> <div class="col-sm-5">
<input id="edit-user-username" type="text" class="form-control" placeholder="用户账号,也就是用户登录名"/> <input id="edit-user-username" type="text" class="form-control"
placeholder="用户账号,也就是用户登录名"/>
</div> </div>
<div class="col-sm-5"> <div class="col-sm-5">
<div class="control-desc">英文字符和数字最大32字符</div> <div class="control-desc">英文字符和数字最大32字符</div>
@ -236,12 +260,16 @@
## <li><div id="sec-auth-username-password" class="tp-checkbox">用户名 + 密码</div></li> ## <li><div id="sec-auth-username-password" class="tp-checkbox">用户名 + 密码</div></li>
<li> <li>
<div id="sec-auth-username-password-captcha" class="tp-checkbox">用户名 + 密码 + 验证码</div> <div id="sec-auth-username-password-captcha" class="tp-checkbox">用户名 + 密码 +
验证码
</div>
</li> </li>
## <li><div id="sec-auth-username-oath" class="tp-checkbox">用户名 + 身份认证器动态密码</div></li> ## <li><div id="sec-auth-username-oath" class="tp-checkbox">用户名 + 身份认证器动态密码</div></li>
<li> <li>
<div id="sec-auth-username-password-oath" class="tp-checkbox">用户名 + 密码 + 身份认证器动态密码</div> <div id="sec-auth-username-password-oath" class="tp-checkbox">用户名 + 密码 +
身份认证器动态密码
</div>
</li> </li>
</ul> </ul>
</div> </div>
@ -255,11 +283,16 @@
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-sm-8"> <div class="col-sm-8">
<div id="edit-user-message" class="alert alert-danger" style="text-align:left;display:none;"></div> <div id="edit-user-message" class="alert alert-danger"
style="text-align:left;display:none;"></div>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<button type="button" class="btn btn-sm btn-primary" id="btn-edit-user-save"><i class="fa fa-check fa-fw"></i> 确定</button> <button type="button" class="btn btn-sm btn-primary" id="btn-edit-user-save"><i
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-times fa-fw"></i> 取消</button> class="fa fa-check fa-fw"></i> 确定
</button>
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i
class="fa fa-times fa-fw"></i> 取消
</button>
</div> </div>
</div> </div>
</div> </div>
@ -271,7 +304,8 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 data-field="dlg-title" class="modal-title"></h3> <h3 data-field="dlg-title" class="modal-title"></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -287,8 +321,12 @@
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<div class="col-sm-10 col-sm-offset-1"> <div class="col-sm-10 col-sm-offset-1">
<div id="can-send-email" style="display:none"> <div id="can-send-email" style="display:none">
<div> 向用户绑定的邮箱地址 <span data-field="email" class="mono"></span> 发送密码重置邮件,然后用户可通过邮件中的密码重置链接自行设置新密码。</div> <div> 向用户绑定的邮箱地址 <span data-field="email" class="mono"></span>
<button type="button" class="btn btn-sm btn-primary" id="btn-send-reset-email" style="margin-top:10px;"><i class="fa fa-send fa-fw"></i> 发送邮件</button> 发送密码重置邮件,然后用户可通过邮件中的密码重置链接自行设置新密码。
</div>
<button type="button" class="btn btn-sm btn-primary" id="btn-send-reset-email"
style="margin-top:10px;"><i class="fa fa-send fa-fw"></i> 发送邮件
</button>
</div> </div>
<div id="cannot-send-email" class="alert alert-warning" style="margin-top:10px;"> <div id="cannot-send-email" class="alert alert-warning" style="margin-top:10px;">
<i class="fas fa-exclamation-triangle fa-fw"></i> <span id="msg-cannot-send-email">用户未设置邮箱</span>,密码重置邮件功能无法使用,请使用手动重置方式。 <i class="fas fa-exclamation-triangle fa-fw"></i> <span id="msg-cannot-send-email">用户未设置邮箱</span>,密码重置邮件功能无法使用,请使用手动重置方式。
@ -316,18 +354,25 @@
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<div class="col-sm-5 col-sm-offset-1"> <div class="col-sm-5 col-sm-offset-1">
<div class="input-group"> <div class="input-group">
<input data-field="password" type="password" class="form-control mono" placeholder="设置用户的新密码"> <input data-field="password" type="password" class="form-control mono"
<span class="input-group-btn"><button class="btn btn-sm btn-default" type="button" id="btn-switch-password"><i class="fa fa-eye fa-fw"></i></button></span> placeholder="设置用户的新密码">
<span class="input-group-btn"><button class="btn btn-sm btn-default" type="button"
id="btn-switch-password"><i
class="fa fa-eye fa-fw"></i></button></span>
</div> </div>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<button type="button" class="btn btn-sm btn-info" id="btn-gen-random-password"><i class="far fa-snowflake fa-fw"></i> 生成随机密码</button> <button type="button" class="btn btn-sm btn-info" id="btn-gen-random-password"><i
class="far fa-snowflake fa-fw"></i> 生成随机密码
</button>
</div> </div>
</div> </div>
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<div class="col-sm-6 col-sm-offset-1"> <div class="col-sm-6 col-sm-offset-1">
<button type="button" class="btn btn-sm btn-primary" id="btn-reset-password"><i class="fa fa-check fa-fw"></i> 重置密码</button> <button type="button" class="btn btn-sm btn-primary" id="btn-reset-password"><i
class="fa fa-check fa-fw"></i> 重置密码
</button>
</div> </div>
</div> </div>
@ -338,10 +383,13 @@
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-sm-8"> <div class="col-sm-8">
<div id="edit-user-message" class="alert alert-danger" style="text-align:left;display:none;"></div> <div id="edit-user-message" class="alert alert-danger"
style="text-align:left;display:none;"></div>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-times fa-fw"></i> 取消</button> <button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i
class="fa fa-times fa-fw"></i> 取消
</button>
</div> </div>
</div> </div>
</div> </div>
@ -353,24 +401,29 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 class="modal-title">导入用户</h3> <h3 class="modal-title">导入用户</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div style="text-align:center;margin:10px 0 20px 0;"> <div style="text-align:center;margin:10px 0 20px 0;">
<p>请点击图标,选择要上传的文件!</p> <p>请点击图标,选择要上传的文件!</p>
<p><a href="/static/download/teleport-example-user.csv"><i class="fa fa-download fa-fw"></i>下载用户信息文件模板</a></p> <p><a href="/static/download/teleport-example-user.csv"><i class="fa fa-download fa-fw"></i>下载用户信息文件模板</a>
</p>
</div> </div>
<div style="text-align:center;"> <div style="text-align:center;">
<i id="btn-select-file" class="upload-button far fa-file-alt fa-fw"></i> <i id="btn-select-file" class="upload-button far fa-file-alt fa-fw"></i>
</div> </div>
<div style="text-align:center;margin:10px;" id="upload-file-info">- 尚未选择文件 -</div> <div style="text-align:center;margin:10px;" id="upload-file-info">- 尚未选择文件 -</div>
<div style="text-align:center;"> <div style="text-align:center;">
<div id="upload-file-message" style="display:none;margin:10px;text-align: left;" class="alert alert-info"> <div id="upload-file-message" style="display:none;margin:10px;text-align: left;"
class="alert alert-info">
<i class="fa fa-cog fa-spin fa-fw"></i> 正在导入,请稍候... <i class="fa fa-cog fa-spin fa-fw"></i> 正在导入,请稍候...
</div> </div>
<button type="button" class="btn btn-sm btn-primary" id="btn-do-upload-file" style="display:none;margin:10px;"><i class="fa fa-upload fa-fw"></i> 开始导入</button> <button type="button" class="btn btn-sm btn-primary" id="btn-do-upload-file"
style="display:none;margin:10px;"><i class="fa fa-upload fa-fw"></i> 开始导入
</button>
</div> </div>
</div> </div>
</div> </div>
@ -381,7 +434,8 @@
<div class="modal-dialog modal-lg" role="document"> <div class="modal-dialog modal-lg" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 class="modal-title">LDAP设置 (实验性)</h3> <h3 class="modal-title">LDAP设置 (实验性)</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -391,14 +445,16 @@
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<label for="edit-ldap-server" class="col-sm-2 control-label require">LDAP主机</label> <label for="edit-ldap-server" class="col-sm-2 control-label require">LDAP主机</label>
<div class="col-sm-4"> <div class="col-sm-4">
<input id="edit-ldap-server" type="text" class="form-control" placeholder="LDAP服务器IP或域名" /> <input id="edit-ldap-server" type="text" class="form-control"
placeholder="LDAP服务器IP或域名"/>
</div> </div>
</div> </div>
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<label for="edit-ldap-port" class="col-sm-2 control-label require">端口:</label> <label for="edit-ldap-port" class="col-sm-2 control-label require">端口:</label>
<div class="col-sm-4"> <div class="col-sm-4">
<input id="edit-ldap-port" type="text" class="form-control" placeholder="LDAP端口默认为389" /> <input id="edit-ldap-port" type="text" class="form-control"
placeholder="LDAP端口默认为389"/>
</div> </div>
</div> </div>
@ -408,7 +464,8 @@
<input id="edit-ldap-domain" type="text" class="form-control" placeholder=""/> <input id="edit-ldap-domain" type="text" class="form-control" placeholder=""/>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
<div class="control-desc-sm">LDAP的账号使用 <span class="important">用户名@域</span> 来登录teleport。</div> <div class="control-desc-sm">LDAP的账号使用 <span class="important">用户名@域</span> 来登录teleport。
</div>
</div> </div>
</div> </div>
@ -426,8 +483,11 @@
<label for="edit-ldap-password" class="col-sm-2 control-label require">密码:</label> <label for="edit-ldap-password" class="col-sm-2 control-label require">密码:</label>
<div class="col-sm-4"> <div class="col-sm-4">
<div class="input-group"> <div class="input-group">
<input id="edit-ldap-password" type="password" class="form-control mono" placeholder="" /> <input id="edit-ldap-password" type="password" class="form-control mono"
<span class="input-group-btn"><button class="btn btn-sm btn-default" type="button" id="btn-switch-ldap-password"><i class="fa fa-eye fa-fw"></i></button></span> placeholder=""/>
<span class="input-group-btn"><button class="btn btn-sm btn-default" type="button"
id="btn-switch-ldap-password"><i
class="fa fa-eye fa-fw"></i></button></span>
</div> </div>
</div> </div>
<div class="col-sm-6"> <div class="col-sm-6">
@ -445,23 +505,29 @@
<label for="edit-ldap-base-dn" class="col-sm-2 control-label require">用户基准DN</label> <label for="edit-ldap-base-dn" class="col-sm-2 control-label require">用户基准DN</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input id="edit-ldap-base-dn" type="text" class="form-control" placeholder=""/> <input id="edit-ldap-base-dn" type="text" class="form-control" placeholder=""/>
<div class="control-desc-sm">限制用户DN的范围例如 <span class="important">ou=dev,ou=company,ou=com</span>。用户的完整DN为 <span class="important">cn=用户登录名,用户基准DN</span>。</div> <div class="control-desc-sm">限制用户DN的范围例如 <span class="important">ou=dev,ou=company,ou=com</span>。用户的完整DN为
<span class="important">cn=用户登录名,用户基准DN</span>。
</div>
</div> </div>
</div> </div>
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<label for="edit-ldap-filter" class="col-sm-2 control-label require">过滤器:</label> <label for="edit-ldap-filter" class="col-sm-2 control-label require">过滤器:</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input id="edit-ldap-filter" type="text" class="form-control" placeholder="" value="(&(objectClass=person))"/> <input id="edit-ldap-filter" type="text" class="form-control" placeholder=""
<div class="control-desc-sm">列举用户时的过滤器,例如 <span class="important">(&(objectClass=person))</span>。</div> value="(&(objectClass=person))"/>
<div class="control-desc-sm">列举用户时的过滤器,例如 <span class="important">(&(objectClass=person))</span>。
</div>
</div> </div>
</div> </div>
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<label for="edit-ldap-attr-map" class="col-sm-2 control-label require">属性映射:</label> <label for="edit-ldap-attr-map" class="col-sm-2 control-label require">属性映射:</label>
<div class="col-sm-9"> <div class="col-sm-9">
<textarea id="edit-ldap-attr-map" class="form-control" style="resize:vertical;height:8em;" placeholder="">t</textarea> <textarea id="edit-ldap-attr-map" class="form-control"
<div class="control-desc-sm">将LDAP的属性映射到 teleport 的用户属性,例如 <span class="important">LDAP中的用户属性 sAMAccountName 映射为teleport的登录账号</span>。如果不清楚此LDAP服务的用户属性可使用下方的“列举属性”按钮进行查询。</div> style="resize:vertical;height:8em;" placeholder="">t</textarea>
<div class="control-desc-sm">将LDAP的属性映射到 teleport 的用户属性,例如 <span class="important">LDAP中的用户属性 sAMAccountName 映射为teleport的登录账号</span>。如果不清楚此LDAP服务的用户属性可使用下方的“列举属性”按钮进行查询。
</div>
</div> </div>
</div> </div>
@ -472,13 +538,22 @@
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
<div id="edit-user-message" class="alert alert-danger" style="text-align:left;display:none;"></div> <div id="edit-user-message" class="alert alert-danger"
style="text-align:left;display:none;"></div>
</div> </div>
<div class="col-sm-6" style="text-align:right;"> <div class="col-sm-6" style="text-align:right;">
<button type="button" class="btn btn-sm btn-success" id="btn-ldap-config-list-attr"><i class="fa fa-list-alt fa-fw"></i> 列举属性</button> <button type="button" class="btn btn-sm btn-success" id="btn-ldap-config-list-attr"><i
<button type="button" class="btn btn-sm btn-success" id="btn-ldap-config-test"><i class="fa fa-bolt fa-fw"></i> 测试获取用户</button> class="fa fa-list-alt fa-fw"></i> 列举属性
<button type="button" class="btn btn-sm btn-primary" id="btn-ldap-config-save"><i class="fa fa-check fa-fw"></i> 保存设置</button> </button>
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-times fa-fw"></i> 取消</button> <button type="button" class="btn btn-sm btn-success" id="btn-ldap-config-test"><i
class="fa fa-bolt fa-fw"></i> 测试获取用户
</button>
<button type="button" class="btn btn-sm btn-primary" id="btn-ldap-config-save"><i
class="fa fa-check fa-fw"></i> 保存设置
</button>
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i
class="fa fa-times fa-fw"></i> 取消
</button>
</div> </div>
</div> </div>
</div> </div>
@ -490,7 +565,8 @@
<div class="modal-dialog" style="margin-top:50px;"> <div class="modal-dialog" style="margin-top:50px;">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 class="modal-title">LDAP用户属性一览</h3> <h3 class="modal-title">LDAP用户属性一览</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -503,7 +579,8 @@
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<div class="col-sm-12"> <div class="col-sm-12">
<div id="msg-ldap-list-attr-ret" style="height:20em;overflow:scroll;padding:5px;border: 1px solid #747474;"></div> <div id="msg-ldap-list-attr-ret"
style="height:20em;overflow:scroll;padding:5px;border: 1px solid #747474;"></div>
</div> </div>
</div> </div>
@ -514,7 +591,9 @@
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-sm-12" style="text-align:right;"> <div class="col-sm-12" style="text-align:right;">
<button type="button" class="btn btn-sm btn-primary" data-dismiss="modal"><i class="fa fa-check fa-fw"></i> 确定</button> <button type="button" class="btn btn-sm btn-primary" data-dismiss="modal"><i
class="fa fa-check fa-fw"></i> 确定
</button>
</div> </div>
</div> </div>
</div> </div>
@ -526,7 +605,8 @@
<div class="modal-dialog" style="margin-top:50px;"> <div class="modal-dialog" style="margin-top:50px;">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 class="modal-title">LDAP连接测试结果</h3> <h3 class="modal-title">LDAP连接测试结果</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
@ -539,7 +619,8 @@
<div class="form-group form-group-sm"> <div class="form-group form-group-sm">
<div class="col-sm-12"> <div class="col-sm-12">
<table id="table-ldap-test-ret" class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table> <table id="table-ldap-test-ret"
class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table>
</div> </div>
</div> </div>
@ -550,7 +631,9 @@
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-sm-12" style="text-align:right;"> <div class="col-sm-12" style="text-align:right;">
<button type="button" class="btn btn-sm btn-primary" data-dismiss="modal"><i class="fa fa-check fa-fw"></i> 确定</button> <button type="button" class="btn btn-sm btn-primary" data-dismiss="modal"><i
class="fa fa-check fa-fw"></i> 确定
</button>
</div> </div>
</div> </div>
</div> </div>
@ -562,33 +645,61 @@
<div class="modal-dialog modal-lg" style="margin-top:50px;"> <div class="modal-dialog modal-lg" style="margin-top:50px;">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times-circle fa-fw"></i></button> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fa fa-times-circle fa-fw"></i></button>
<h3 class="modal-title">导入LDAP用户(试验)</h3> <h3 class="modal-title">导入LDAP用户(试验)</h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-horizontal"> <div class="table-prefix-area">
<div style="margin-bottom:8px;"> <div class="table-extend-cell">
LDAP用户列表 <span class="table-name"><i class="fa fa-list fa-fw"></i> LDAP用户列表</span>
</div> <button id="btn-ldap-import-refresh" class="btn btn-sm btn-default"><i class="fa fa-redo fa-fw"></i> 刷新列表</button>
<div class="form-group form-group-sm">
<div class="col-sm-12">
<table id="table-ldap-import" class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table>
</div> </div>
</div> </div>
<table id="table-ldap-user-list"
class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table>
<div class="table-extend-area">
<div class="table-extend-cell checkbox-select-all">
<input id="table-ldap-user-select-all" type="checkbox"/>
</div> </div>
<div class="table-extend-cell group-actions">
<div class="btn-group" role="group">
<button id="btn-ldap-import-import" type="button" class="btn btn-primary">
<i class="fas fa-address-book fa-fw"></i> 导入选中的用户
</button>
</div>
</div>
</div>
## <div class="form-horizontal">
## <div style="margin-bottom:8px;">
## LDAP用户列表
## </div>
##
## <div class="form-group form-group-sm">
##
## <div class="col-sm-12">
## <table id="table-ldap-user-list"
## class="table table-striped table-bordered table-hover table-data no-footer dtr-inline"></table>
## </div>
##
## </div>
##
## </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col-sm-12" style="text-align:right;"> <div class="col-sm-12" style="text-align:right;">
<button type="button" class="btn btn-sm btn-success" id="btn-ldap-import-refresh"><i class="fa fa-redo fa-fw"></i> 刷新列表</button> <button type="button" class="btn btn-sm btn-default" data-dismiss="modal">
<button type="button" class="btn btn-sm btn-primary" id="btn-ldap-import-import"><i class="fa fa-check fa-fw"></i> 导入选中用户</button> <i class="fa fa-times fa-fw"></i> 关闭
<button type="button" class="btn btn-sm btn-default" data-dismiss="modal"><i class="fa fa-times fa-fw"></i> 取消</button> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,6 +9,13 @@ TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH = 0x0008 # 用户名+密码+OATH
APP_MODE_NORMAL = 1 APP_MODE_NORMAL = 1
APP_MODE_MAINTENANCE = 2 APP_MODE_MAINTENANCE = 2
# ==========================================================================
# 用户类型
# ==========================================================================
TP_USER_TYPE_NONE = 0
TP_USER_TYPE_LOCAL = 1
TP_USER_TYPE_LDAP = 2
# ========================================================================== # ==========================================================================
# 远程主机账号认证方式 # 远程主机账号认证方式
# ========================================================================== # ==========================================================================

View File

@ -258,6 +258,9 @@ controllers = [
(r'/system/do-ldap-config-test', system.DoLdapConfigTestHandler), (r'/system/do-ldap-config-test', system.DoLdapConfigTestHandler),
# - [json] 获取LDAP用户列表 # - [json] 获取LDAP用户列表
(r'/system/do-ldap-get-users', system.DoLdapGetUsersHandler), (r'/system/do-ldap-get-users', system.DoLdapGetUsersHandler),
# - [json] 导入LDAP用户
(r'/system/do-ldap-import', system.DoLdapImportHandler),
# #
# - [json] 获取服务器时间 # - [json] 获取服务器时间
(r'/system/get-time', system.DoGetTimeHandler), (r'/system/get-time', system.DoGetTimeHandler),

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime import datetime
import hashlib
import json import json
import shutil import shutil
@ -17,6 +18,7 @@ from app.model import syslog
from app.model import record from app.model import record
from app.model import ops from app.model import ops
from app.model import audit from app.model import audit
from app.model import user
from app.base.core_server import core_service_async_post_http from app.base.core_server import core_service_async_post_http
from app.base.session import tp_session from app.base.session import tp_session
from app.logic.auth.ldap import Ldap from app.logic.auth.ldap import Ldap
@ -515,7 +517,7 @@ class DoLdapGetUsersHandler(TPBaseJsonHandler):
try: try:
if len(tp_cfg().sys_ldap_password) == 0: if len(tp_cfg().sys_ldap_password) == 0:
return self.write_json(TPE_PARAM, message='需要设置LDAP管理员密码') return self.write_json(TPE_PARAM, message='LDAP未能正确配置,需要管理员密码')
else: else:
_password = tp_cfg().sys_ldap_password _password = tp_cfg().sys_ldap_password
_server = tp_cfg().sys.ldap.server _server = tp_cfg().sys.ldap.server
@ -535,14 +537,180 @@ class DoLdapGetUsersHandler(TPBaseJsonHandler):
return self.write_json(ret, message=err_msg) return self.write_json(ret, message=err_msg)
else: else:
# TODO: search all user in database to check if the LDAP user have already bind. # TODO: search all user in database to check if the LDAP user have already bind.
ret_data = []
for u in data: for u in data:
data[u]['bind'] = False h = hashlib.sha1()
return self.write_json(ret, data=data) h.update(u.encode())
user = data[u]
user['bind'] = False
user['id'] = h.hexdigest()
ret_data.append(user)
return self.write_json(ret, data=ret_data)
except: except:
log.e('') log.e('')
return self.write_json(TPE_PARAM) return self.write_json(TPE_PARAM)
class DoLdapImportHandler(TPBaseJsonHandler):
@tornado.gen.coroutine
def post(self):
ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE)
if ret != TPE_OK:
return
args = self.get_argument('args', None)
if args is None:
return self.write_json(TPE_PARAM)
try:
args = json.loads(args)
except:
return self.write_json(TPE_JSON_FORMAT)
try:
dn_hash_list = args['ldap_users']
if len(tp_cfg().sys_ldap_password) == 0:
return self.write_json(TPE_PARAM, message='LDAP未能正确配置需要管理员密码')
else:
_password = tp_cfg().sys_ldap_password
_server = tp_cfg().sys.ldap.server
_port = tp_cfg().sys.ldap.port
_admin = tp_cfg().sys.ldap.admin
_base_dn = tp_cfg().sys.ldap.base_dn
_filter = tp_cfg().sys.ldap.filter
_attr_map = tp_cfg().sys.ldap.attr_map
except:
return self.write_json(TPE_PARAM)
try:
ldap = Ldap(_server, _port, _base_dn)
ret, data, err_msg = ldap.list_users(_admin, _password, _filter, _attr_map)
if ret != TPE_OK:
return self.write_json(ret, message=err_msg)
else:
# TODO: search all user in database to check if the LDAP user have already bind.
need_import = []
for u in data:
h = hashlib.sha1()
h.update(u.encode())
dn_hash = h.hexdigest()
for x in dn_hash_list:
if x == dn_hash:
_user = data[u]
_user['dn'] = u
need_import.append(_user)
break
if len(need_import) == 0:
return self.write_json(ret, message='没有可以导入的LDAP用户')
return self._do_import(need_import)
except:
log.e('')
return self.write_json(TPE_PARAM)
def _do_import(self, users):
success = list()
failed = list()
try:
user_list = []
for _u in users:
u = dict()
u['_line'] = 0
u['_id'] = 0
u['type'] = TP_USER_TYPE_LDAP
u['ldap_dn'] = _u['dn']
u['username'] = '{}@{}'.format(_u['username'], tp_cfg().sys.ldap.domain)
u['surname'] = _u['surname']
u['email'] = _u['email']
u['mobile'] = ''
u['qq'] = ''
u['wechat'] = ''
u['desc'] = ''
u['password'] = ''
# fix
if len(u['surname']) == 0:
u['surname'] = u['username']
u['username'] = u['username'].lower()
user_list.append(u)
user.create_users(self, user_list, success, failed)
# 对于创建成功的用户,发送密码邮件函
sys_smtp_password = tp_cfg().sys_smtp_password
if len(sys_smtp_password) > 0:
web_url = '{}://{}'.format(self.request.protocol, self.request.host)
for u in user_list:
if u['_id'] == 0 or len(u['email']) == 0:
continue
mmm = '{surname} 您好!\n\n已为您创建teleport系统用户账号现在可以使用以下信息登录teleport系统\n\n'
'登录用户名:{username}\n'
'密码:您正在使用的密码\n'
'地址:{web_url}\n\n\n\n'
'[本邮件由teleport系统自动发出请勿回复]'
'\n\n'
''.format(surname=u['surname'], username=u['username'], web_url=web_url)
print(mmm)
err = TPE_FAILED
msg = 'test bad.'
# err, msg = yield mail.tp_send_mail(
# u['email'],
# '{surname} 您好!\n\n已为您创建teleport系统用户账号现在可以使用以下信息登录teleport系统\n\n'
# '登录用户名:{username}\n'
# '密码:您正在使用的密码\n'
# '地址:{web_url}\n\n\n\n'
# '[本邮件由teleport系统自动发出请勿回复]'
# '\n\n'
# ''.format(surname=u['surname'], username=u['username'], web_url=web_url),
# subject='用户密码函'
# )
if err != TPE_OK:
failed.append({'line': u['_line'], 'error': '无法发送密码函到邮箱 {},错误:{}'.format(u['email'], msg)})
# 统计结果
total_success = 0
total_failed = 0
for u in user_list:
if u['_id'] == 0:
total_failed += 1
else:
total_success += 1
# 生成最终结果信息
if len(failed) == 0:
# ret['code'] = TPE_OK
# ret['message'] = '共导入 {} 个用户账号!'.format(total_success)
return self.write_json(TPE_OK, message='共导入 {} 个用户账号!'.format(total_success))
else:
# ret['code'] = TPE_FAILED
msg = ''
if total_success > 0:
msg = '{} 个用户账号导入成功,'.format(total_success)
if total_failed > 0:
msg += '{} 个用户账号未能导入!'.format(total_failed)
# ret['data'] = failed
return self.write_json(TPE_FAILED, data=failed, message=msg)
except:
log.e('got exception when import LDAP user.\n')
# ret['code'] = TPE_FAILED
msg = ''
if len(success) > 0:
msg += '{} 个用户账号导入后发生异常!'.format(len(success))
else:
msg = '发生异常!'
# ret['data'] = failed
return self.write_json(TPE_FAILED, data=failed, message=msg)
class DoCleanupStorageHandler(TPBaseJsonHandler): class DoCleanupStorageHandler(TPBaseJsonHandler):
@tornado.gen.coroutine @tornado.gen.coroutine
def post(self): def post(self):
@ -573,5 +741,3 @@ class DoRebuildAuditAuzMapHandler(TPBaseJsonHandler):
err = ops.build_auz_map() err = ops.build_auz_map()
self.write_json(err) self.write_json(err)

View File

@ -194,6 +194,10 @@ def create_users(handler, user_list, success, failed):
for i in range(len(user_list)): for i in range(len(user_list)):
user = user_list[i] user = user_list[i]
if 'type' not in user:
user['type'] = TP_USER_TYPE_LOCAL
if 'ldap_dn' not in user:
user['ldap_dn'] = ''
err = s.reset().select_from('user', ['id']).where('user.username="{}"'.format(user['username'])).query() err = s.reset().select_from('user', ['id']).where('user.username="{}"'.format(user['username'])).query()
if err != TPE_OK: if err != TPE_OK:
@ -202,11 +206,14 @@ def create_users(handler, user_list, success, failed):
failed.append({'line': user['_line'], 'error': '账号 `{}` 已经存在'.format(user['username'])}) failed.append({'line': user['_line'], 'error': '账号 `{}` 已经存在'.format(user['username'])})
continue continue
if user['type'] == TP_USER_TYPE_LOCAL:
_password = tp_password_generate_secret(user['password']) _password = tp_password_generate_secret(user['password'])
else:
_password = ''
sql = 'INSERT INTO `{}user` (`type`, `auth_type`, `password`, `username`, `surname`, `role_id`, `state`, `email`, `creator_id`, `create_time`, `last_login`, `last_chpass`, `desc`) VALUES ' \ sql = 'INSERT INTO `{}user` (`type`, `auth_type`, `password`, `username`, `surname`, `role_id`, `state`, `email`, `creator_id`, `create_time`, `last_login`, `last_chpass`, `desc`) VALUES ' \
'(1, 0, "{password}", "{username}", "{surname}", 0, {state}, "{email}", {creator_id}, {create_time}, {last_login}, {last_chpass}, "{desc}");' \ '({user_type}, 0, "{password}", "{username}", "{surname}", 0, {state}, "{email}", {creator_id}, {create_time}, {last_login}, {last_chpass}, "{desc}");' \
''.format(db.table_prefix, ''.format(db.table_prefix, user_type=user['type'],
username=user['username'], surname=user['surname'], password=_password, state=TP_STATE_NORMAL, email=user['email'], username=user['username'], surname=user['surname'], password=_password, state=TP_STATE_NORMAL, email=user['email'],
creator_id=operator['id'], create_time=_time_now, last_login=0, last_chpass=0, desc=user['desc']) creator_id=operator['id'], create_time=_time_now, last_login=0, last_chpass=0, desc=user['desc'])
db_ret = db.exec(sql) db_ret = db.exec(sql)