Adding Operator role

This commit is contained in:
Khanh Ngo 2018-08-31 11:57:06 +07:00
parent 5e6806cc0f
commit 3457d9214a
10 changed files with 228 additions and 133 deletions

View File

@ -6,6 +6,9 @@ from app.models import Role, Setting
def admin_role_required(f):
"""
Grant access if user is in Administrator role
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user.role.name != 'Administrator':
@ -14,10 +17,28 @@ def admin_role_required(f):
return decorated_function
def can_access_domain(f):
def operator_role_required(f):
"""
Grant access if user is in Operator role or higher
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user.role.name != 'Administrator':
if g.user.role.name not in ['Administrator', 'Operator']:
return redirect(url_for('error', code=401))
return f(*args, **kwargs)
return decorated_function
def can_access_domain(f):
"""
Grant access if:
- user is in Operator role or higher, or
- user is in granted Account, or
- user is in granted Domain
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user.role.name not in ['Administrator', 'Operator']:
domain_name = kwargs.get('domain_name')
user_domain = [d.name for d in g.user.get_domain()]
@ -29,10 +50,15 @@ def can_access_domain(f):
def can_configure_dnssec(f):
"""
Grant access if:
- user is in Operator role or higher, or
- dnssec_admins_only is off
"""
@wraps(f)
def decorated_function(*args, **kwargs):
if g.user.role.name != 'Administrator' and Setting().get('dnssec_admins_only'):
return redirect(url_for('error', code=401))
if g.user.role.name not in ['Administrator', 'Operator'] and Setting().get('dnssec_admins_only'):
return redirect(url_for('error', code=401))
return f(*args, **kwargs)
return decorated_function

View File

@ -150,7 +150,7 @@ class User(db.Model):
logging.error(e)
logging.debug('baseDN: {0}'.format(baseDN))
logging.debug(traceback.format_exc())
raise
def ldap_auth(self, ldap_username, password):
try:
@ -165,6 +165,8 @@ class User(db.Model):
"""
Validate user credential
"""
role_name = 'User'
if method == 'LOCAL':
user_info = User.query.filter(User.username == self.username).first()
@ -179,12 +181,12 @@ class User(db.Model):
return False
if method == 'LDAP':
isadmin = False
LDAP_TYPE = Setting().get('ldap_type')
LDAP_BASE_DN = Setting().get('ldap_base_dn')
LDAP_FILTER_BASIC = Setting().get('ldap_filter_basic')
LDAP_FILTER_USERNAME = Setting().get('ldap_filter_username')
LDAP_ADMIN_GROUP = Setting().get('ldap_admin_group')
LDAP_OPERATOR_GROUP = Setting().get('ldap_operator_group')
LDAP_USER_GROUP = Setting().get('ldap_user_group')
LDAP_GROUP_SECURITY_ENABLED = Setting().get('ldap_sg_enabled')
@ -206,24 +208,30 @@ class User(db.Model):
try:
if LDAP_TYPE == 'ldap':
if (self.ldap_search(searchFilter, LDAP_ADMIN_GROUP)):
isadmin = True
role_name = 'Administrator'
logging.info('User {0} is part of the "{1}" group that allows admin access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP))
elif (self.ldap_search(searchFilter, LDAP_OPERATOR_GROUP)):
role_name = 'Operator'
logging.info('User {0} is part of the "{1}" group that allows operator access to PowerDNS-Admin'.format(self.username, LDAP_OPERATOR_GROUP))
elif (self.ldap_search(searchFilter, LDAP_USER_GROUP)):
logging.info('User {0} is part of the "{1}" group that allows user access to PowerDNS-Admin'.format(self.username, LDAP_USER_GROUP))
else:
logging.error('User {0} is not part of the "{1}" or "{2}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_USER_GROUP))
logging.error('User {0} is not part of the "{1}", "{2}" or "{3}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_OPERATOR_GROUP, LDAP_USER_GROUP))
return False
elif LDAP_TYPE == 'ad':
user_ldap_groups = [g.decode("utf-8") for g in ldap_result[0][0][1]['memberOf']]
logging.debug('user_ldap_groups: {0}'.format(user_ldap_groups))
if (LDAP_ADMIN_GROUP in user_ldap_groups):
isadmin = True
role_name = 'Administrator'
logging.info('User {0} is part of the "{1}" group that allows admin access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP))
elif (LDAP_OPERATOR_GROUP in user_ldap_groups):
role_name = 'Operator'
logging.info('User {0} is part of the "{1}" group that allows operator access to PowerDNS-Admin'.format(self.username, LDAP_OPERATOR_GROUP))
elif (LDAP_USER_GROUP in user_ldap_groups):
logging.info('User {0} is part of the "{1}" group that allows user access to PowerDNS-Admin'.format(self.username, LDAP_USER_GROUP))
else:
logging.error('User {0} is not part of the "{1}" or "{2}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_USER_GROUP))
logging.error('User {0} is not part of the "{1}", "{2}" or "{3}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_OPERATOR_GROUP, LDAP_USER_GROUP))
return False
else:
logging.error('Invalid LDAP type')
@ -261,21 +269,17 @@ class User(db.Model):
logging.debug(traceback.format_exc())
# first register user will be in Administrator role
self.role_id = Role.query.filter_by(name='User').first().id
if User.query.count() == 0:
self.role_id = Role.query.filter_by(name='Administrator').first().id
# user will be in Administrator role if part of LDAP Admin group
if LDAP_GROUP_SECURITY_ENABLED:
if isadmin == True:
self.role_id = Role.query.filter_by(name='Administrator').first().id
else:
self.role_id = Role.query.filter_by(name=role_name).first().id
self.create_user()
logging.info('Created user "{0}" in the DB'.format(self.username))
# user already exists in database, set their admin status based on group membership (if enabled)
# user already exists in database, set their role based on group membership (if enabled)
if LDAP_GROUP_SECURITY_ENABLED:
self.set_admin(isadmin)
self.set_role(role_name)
return True
else:
@ -453,28 +457,15 @@ class User(db.Model):
return False
return False
def set_admin(self, is_admin):
"""
Set role for a user:
is_admin == True => Administrator
is_admin == False => User
"""
user_role_name = 'Administrator' if is_admin else 'User'
role = Role.query.filter(Role.name==user_role_name).first()
try:
if role:
user = User.query.filter(User.username==self.username).first()
user.role_id = role.id
db.session.commit()
return True
else:
return False
except:
db.session.roleback()
logging.error('Cannot change user role in DB')
logging.debug(traceback.format_exc())
return False
def set_role(self, role_name):
role = Role.query.filter(Role.name==role_name).first()
if role:
user = User.query.filter(User.username==self.username).first()
user.role_id = role.id
db.session.commit()
return {'status': True, 'msg': 'Set user role successfully'}
else:
return {'status': False, 'msg': 'Role does not exist'}
class Account(db.Model):
@ -1825,8 +1816,9 @@ class Setting(db.Model):
'ldap_filter_basic': '',
'ldap_filter_username': '',
'ldap_sg_enabled': False,
'ldap_admin_group': False,
'ldap_user_group': False,
'ldap_admin_group': '',
'ldap_operator_group': '',
'ldap_user_group': '',
'github_oauth_enabled': False,
'github_oauth_key': '',
'github_oauth_secret': '',

View File

@ -22,9 +22,14 @@ function applyChanges(data, url, showResult, refreshPage) {
},
error : function(jqXHR, status) {
// console.log(jqXHR);
// var modal = $("#modal_error");
// modal.find('.modal-body p').text(jqXHR["responseText"]);
// modal.modal('show');
console.log(jqXHR);
var modal = $("#modal_error");
modal.find('.modal-body p').text(jqXHR["responseText"]);
var responseJson = jQuery.parseJSON(jqXHR.responseText);
modal.find('.modal-body p').text(responseJson['msg']);
modal.modal('show');
}
});

View File

@ -36,7 +36,7 @@
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Admin</th>
<th>Role</th>
<th>Privileges</th>
<th>Action</th>
</tr>
@ -49,18 +49,22 @@
<td>{{ user.lastname }}</td>
<td>{{ user.email }}</td>
<td>
<input type="checkbox" id="{{ user.username }}" class="admin_toggle" {% if user.role.name=='Administrator' %}checked{% endif %} {% if user.username==current_user.username %}disabled{% endif %}>
<select id="{{ user.username }}" class="user_role" {% if user.username==current_user.username or (current_user.role.name=='Operator' and user.role.name=='Administrator') %}disabled{% endif %}>
{% for role in roles %}
<option value="{{ role.name }}" {% if role.id==user.role.id %}selected{% endif %}>{{ role.name }}</option>
{% endfor %}
</select>
</td>
<td width="6%">
<button type="button" class="btn btn-flat btn-warning button_revoke" id="{{ user.username }}">
<button type="button" class="btn btn-flat btn-warning button_revoke" id="{{ user.username }}" {% if current_user.role.name=='Operator' and user.role.name=='Administrator' %}disabled{% endif %}>
Revoke&nbsp;<i class="fa fa-lock"></i>
</button>
</td>
<td width="15%">
<button type="button" class="btn btn-flat btn-success button_edit" onclick="window.location.href='{{ url_for('admin_edituser', user_username=user.username) }}'">
<button type="button" class="btn btn-flat btn-success button_edit" onclick="window.location.href='{{ url_for('admin_edituser', user_username=user.username) }}'" {% if current_user.role.name=='Operator' and user.role.name=='Administrator' %}disabled{% endif %}>
Edit&nbsp;<i class="fa fa-lock"></i>
</button>
<button type="button" class="btn btn-flat btn-danger button_delete" id="{{ user.username }}" {% if user.username==current_user.username %}disabled{% endif %}>
<button type="button" class="btn btn-flat btn-danger button_delete" id="{{ user.username }}" {% if user.username==current_user.username or (current_user.role.name=='Operator' and user.role.name=='Administrator') %}disabled{% endif %}>
Delete&nbsp;<i class="fa fa-trash"></i>
</button>
</td>
@ -93,14 +97,6 @@
"pageLength": 10
});
// avoid losing icheck box style when database refreshed
$('#tbl_users').on('draw.dt', function () {
$('.admin_toggle').iCheck({
handle: 'checkbox',
checkboxClass: 'icheckbox_square-blue'
});
});
// handle revocation of privileges
$(document.body).on('click', '.button_revoke', function() {
var modal = $("#modal_revoke");
@ -129,24 +125,18 @@
});
// initialize pretty checkboxes
$('.admin_toggle').iCheck({
checkboxClass : 'icheckbox_square-blue',
increaseArea : '20%' // optional
});
// handle checkbox toggling
$(document.body).on('ifToggled', '.admin_toggle', function() {
var is_admin = $(this).prop('checked');
// handle user role changing
$('.user_role').on('change', function() {
var role_name = this.value;
var username = $(this).prop('id');
postdata = {
'action' : 'set_admin',
'action' : 'update_user_role',
'data' : {
'username' : username,
'is_admin' : is_admin
'role_name' : role_name
}
};
applyChanges(postdata, $SCRIPT_ROOT + '/admin/manageuser');
applyChanges(postdata, $SCRIPT_ROOT + '/admin/manageuser', showResult=true);
});
</script>
{% endblock %}

View File

@ -133,6 +133,11 @@
<input type="text" class="form-control" name="ldap_admin_group" id="ldap_admin_group" placeholder="e.g. cn=sysops,dc=mydomain,dc=com" data-error="Please input LDAP DN for Admin group" value="{{ SETTING.get('ldap_admin_group') }}">
<span class="help-block with-errors"></span>
</div>
<div class="form-group">
<label for="ldap_operator_group">Operator group</label>
<input type="text" class="form-control" name="ldap_operator_group" id="ldap_operator_group" placeholder="e.g. cn=operators,dc=mydomain,dc=com" data-error="Please input LDAP DN for Operator group" value="{{ SETTING.get('ldap_operator_group') }}">
<span class="help-block with-errors"></span>
</div>
<div class="form-group">
<label for="ldap_user_group">User group</label>
<input type="text" class="form-control" name="ldap_user_group" id="ldap_user_group" placeholder="e.g. cn=users,dc=mydomain,dc=com" data-error="Please input LDAP DN for User group" value="{{ SETTING.get('ldap_user_group') }}">
@ -197,6 +202,9 @@
<li>
Admin group - Your LDAP admin group.
</li>
<li>
Operator group - Your LDAP operator group.
</li>
<li>
User group - Your LDAP user group.
</li>

View File

@ -108,26 +108,26 @@
<li class="{{ 'active' if active_page == 'dashboard' else '' }}">
<a href="{{ url_for('dashboard') }}"><i class="fa fa-dashboard"></i> Dashboard</a>
</li>
{% if current_user.role.name == 'Administrator' %}
{% if current_user.role.name in ['Administrator', 'Operator'] %}
<li class="{{ 'active' if active_page == 'new_domain' else '' }}">
<a href="{{ url_for('domain_add') }}"><i class="fa fa-plus"></i> New Domain</a>
</li>
<li class="header">ADMINISTRATION</li>
<li class="{{ 'active' if active_page == 'admin_console' else '' }}">
<a href="{{ url_for('admin') }}"><i class="fa fa-wrench"></i> Admin Console</a>
</li>
<li class="{{ 'active' if active_page == 'admin_domain_template' else '' }}">
<a href="{{ url_for('templates') }}"><i class="fa fa-clone"></i> Domain Templates</a>
</li>
<li class="{{ 'active' if active_page == 'admin_users' else '' }}">
<a href="{{ url_for('admin_manageuser') }}"><i class="fa fa-users"></i> Users</a>
</li>
<li class="{{ 'active' if active_page == 'admin_accounts' else '' }}">
<a href="{{ url_for('admin_manageaccount') }}"><i class="fa fa-industry"></i> Accounts</a>
<a href="{{ url_for('admin_pdns') }}"><i class="fa fa-info-circle"></i> PDNS</a>
</li>
<li class="{{ 'active' if active_page == 'admin_history' else '' }}">
<a href="{{ url_for('admin_history') }}"><i class="fa fa-calendar"></i> History</a>
</li>
<li class="{{ 'active' if active_page == 'admin_domain_template' else '' }}">
<a href="{{ url_for('templates') }}"><i class="fa fa-clone"></i> Domain Templates</a>
</li>
<li class="{{ 'active' if active_page == 'admin_accounts' else '' }}">
<a href="{{ url_for('admin_manageaccount') }}"><i class="fa fa-industry"></i> Accounts</a>
</li>
<li class="{{ 'active' if active_page == 'admin_users' else '' }}">
<a href="{{ url_for('admin_manageuser') }}"><i class="fa fa-users"></i> Users</a>
</li>
<li class="{{ 'treeview active' if active_page == 'admin_settings' else 'treeview' }}">
<a href="#">
<i class="fa fa-cog"></i> Settings
@ -138,8 +138,10 @@
<ul class="treeview-menu" {% if active_page == 'admin_settings' %}style="display: block;"{% endif %}>
<li><a href="{{ url_for('admin_setting_basic') }}"><i class="fa fa-circle-o"></i></i> Basic</a></li>
<li><a href="{{ url_for('admin_setting_records') }}"><i class="fa fa-circle-o"></i> Records</a></li>
{% if current_user.role.name == 'Administrator' %}
<li><a href="{{ url_for('admin_setting_pdns') }}"><i class="fa fa-circle-o"></i> PDNS</a></li>
<li><a href="{{ url_for('admin_setting_authentication') }}"><i class="fa fa-circle-o"></i> Authentication</a></li>
{% endif %}
</ul>
</li>
{% endif %}

View File

@ -19,7 +19,7 @@
{% block content %}
<!-- Main content -->
<section class="content">
{% if current_user.role.name == 'Administrator' %}
{% if current_user.role.name in ['Administrator', 'Operator'] %}
<div class="row">
<div class="col-xs-3">
<div class="box">
@ -69,7 +69,7 @@
</a>
</div>
<div class="col-lg-6">
<a href="{{ url_for('admin') }}">
<a href="{{ url_for('admin_pdns') }}">
<div class="small-box bg-green">
<div class="inner">
<h3><span style="font-size: 18px">{{ uptime|display_second_to_time }}</span></h3>
@ -102,17 +102,17 @@
</thead>
<tbody>
{% for history in histories %}
<tr class="odd">
<td>{{ history.created_by }}</td>
<td>{{ history.msg }}</td>
<td>{{ history.created_on }}</td>
<td width="6%">
<button type="button" class="btn btn-flat btn-primary history-info-button" value='{{ history.detail|replace("[]","None") }}'>
Info&nbsp;<i class="fa fa-info"></i>
</button>
</td>
</tr>
{% endfor %}
<tr class="odd">
<td>{{ history.created_by }}</td>
<td>{{ history.msg }}</td>
<td>{{ history.created_on }}</td>
<td width="6%">
<button type="button" class="btn btn-flat btn-primary history-info-button" value='{{ history.detail|replace("[]","None") }}'>
Info&nbsp;<i class="fa fa-info"></i>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
@ -136,7 +136,7 @@
<th>Serial</th>
<th>Master</th>
<th>Account</th>
<th {% if current_user.role.name !='Administrator' %}width="6%"{% else %}width="25%"{% endif %}>Action</th>
<th {% if current_user.role.name not in ['Administrator','Operator'] %}width="6%"{% else %}width="25%"{% endif %}>Action</th>
</tr>
</thead>
<tbody>
@ -182,7 +182,7 @@
"ordering" : true,
"columnDefs": [
{ "orderable": false, "targets": [-1] }
{% if current_user.role.name != 'Administrator' %},{ "visible": false, "targets": [-2] }{% endif %}
{% if current_user.role.name not in ['Administrator', 'Operator'] %},{ "visible": false, "targets": [-2] }{% endif %}
],
"processing" : true,
"serverSide" : true,
@ -236,7 +236,7 @@
modal.modal('show');
});
{% if current_user.role.name == 'Administrator' or not SETTING.get('dnssec_admins_only') %}
{% if current_user.role.name in ['Administrator', 'Operator'] or not SETTING.get('dnssec_admins_only') %}
$(document.body).on("click", ".button_dnssec", function() {
var domain = $(this).prop('id');
getdnssec($SCRIPT_ROOT + '/domain/' + domain + '/dnssec', domain);

View File

@ -23,13 +23,13 @@
{% endmacro %}
{% macro account(domain) %}
{% if current_user.role.name =='Administrator' %}
{% if current_user.role.name in ['Administrator', 'Operator'] %}
{% if domain.account_description != "" %}{{ domain.account.description }} {% endif %}[{{ domain.account.name }}]
{% endif %}
{% endmacro %}
{% macro actions(domain) %}
{% if current_user.role.name =='Administrator' %}
{% if current_user.role.name in ['Administrator', 'Operator'] %}
<td width="25%">
<button type="button" class="btn btn-flat btn-success button_template" id="{{ domain.name }}">
Template&nbsp;<i class="fa fa-clone"></i>

View File

@ -22,7 +22,7 @@ from .models import User, Account, Domain, Record, Role, Server, History, Anonym
from app import app, login_manager
from app.lib import utils
from app.oauth import github_oauth, google_oauth
from app.decorators import admin_role_required, can_access_domain, can_configure_dnssec
from app.decorators import admin_role_required, operator_role_required, can_access_domain, can_configure_dnssec
if app.config['SAML_ENABLED']:
from onelogin.saml2.auth import OneLogin_Saml2_Auth
@ -68,7 +68,7 @@ def before_request():
# check site maintenance mode
maintenance = Setting().get('maintenance')
if maintenance and current_user.is_authenticated and current_user.role.name != 'Administrator':
if maintenance and current_user.is_authenticated and current_user.role.name not in ['Administrator', 'Operator']:
return render_template('maintenance.html')
@ -476,7 +476,7 @@ def dashboard():
@app.route('/dashboard-domains', methods=['GET'])
@login_required
def dashboard_domains():
if current_user.role.name == 'Administrator':
if current_user.role.name in ['Administrator', 'Operator']:
domains = Domain.query
else:
domains = User(id=current_user.id).get_domain_query()
@ -508,7 +508,7 @@ def dashboard_domains():
start = "" if search.startswith("^") else "%"
end = "" if search.endswith("$") else "%"
if current_user.role.name == 'Administrator':
if current_user.role.name in ['Administrator', 'Operator']:
domains = domains.outerjoin(Account).filter(Domain.name.ilike(start + search.strip("^$") + end) |
Account.name.ilike(start + search.strip("^$") + end) |
Account.description.ilike(start + search.strip("^$") + end))
@ -603,7 +603,7 @@ def domain(domain_name):
@app.route('/admin/domain/add', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def domain_add():
templates = DomainTemplate.query.all()
if request.method == 'POST':
@ -661,7 +661,7 @@ def domain_add():
@app.route('/admin/domain/<path:domain_name>/delete', methods=['GET'])
@login_required
@admin_role_required
@operator_role_required
def domain_delete(domain_name):
d = Domain()
result = d.delete(domain_name)
@ -677,7 +677,7 @@ def domain_delete(domain_name):
@app.route('/admin/domain/<path:domain_name>/manage', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def domain_management(domain_name):
if request.method == 'GET':
domain = Domain.query.filter(Domain.name == domain_name).first()
@ -712,7 +712,7 @@ def domain_management(domain_name):
@app.route('/admin/domain/<path:domain_name>/change_soa_setting', methods=['POST'])
@login_required
@admin_role_required
@operator_role_required
def domain_change_soa_edit_api(domain_name):
domain = Domain.query.filter(Domain.name == domain_name).first()
if not domain:
@ -738,7 +738,7 @@ def domain_change_soa_edit_api(domain_name):
@app.route('/admin/domain/<path:domain_name>/change_account', methods=['POST'])
@login_required
@admin_role_required
@operator_role_required
def domain_change_account(domain_name):
domain = Domain.query.filter(Domain.name == domain_name).first()
if not domain:
@ -816,7 +816,7 @@ def record_update(domain_name):
@app.route('/domain/<path:domain_name>/record/<path:record_name>/type/<path:record_type>/delete', methods=['GET'])
@login_required
@admin_role_required
@operator_role_required
def record_delete(domain_name, record_name, record_type):
try:
r = Record(name=record_name, type=record_type)
@ -873,7 +873,7 @@ def domain_dnssec_disable(domain_name):
@app.route('/domain/<path:domain_name>/managesetting', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_setdomainsetting(domain_name):
if request.method == 'POST':
#
@ -914,7 +914,7 @@ def admin_setdomainsetting(domain_name):
@app.route('/templates', methods=['GET', 'POST'])
@app.route('/templates/list', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def templates():
templates = DomainTemplate.query.all()
return render_template('template.html', templates=templates)
@ -922,7 +922,7 @@ def templates():
@app.route('/template/create', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def create_template():
if request.method == 'GET':
return render_template('template_add.html')
@ -955,7 +955,7 @@ def create_template():
@app.route('/template/createfromzone', methods=['POST'])
@login_required
@admin_role_required
@operator_role_required
def create_template_from_zone():
try:
jdata = request.json
@ -1015,7 +1015,7 @@ def create_template_from_zone():
@app.route('/template/<path:template>/edit', methods=['GET'])
@login_required
@admin_role_required
@operator_role_required
def edit_template(template):
try:
t = DomainTemplate.query.filter(DomainTemplate.name == template).first()
@ -1066,7 +1066,7 @@ def apply_records(template):
@app.route('/template/<path:template>/delete', methods=['GET'])
@login_required
@admin_role_required
@operator_role_required
def delete_template(template):
try:
t = DomainTemplate.query.filter(DomainTemplate.name == template).first()
@ -1085,10 +1085,10 @@ def delete_template(template):
return redirect(url_for('templates'))
@app.route('/admin', methods=['GET', 'POST'])
@app.route('/admin/pdns', methods=['GET'])
@login_required
@admin_role_required
def admin():
@operator_role_required
def admin_pdns():
if not Setting().get('pdns_api_url') or not Setting().get('pdns_api_key') or not Setting().get('pdns_version'):
return redirect(url_for('admin_setting_pdns'))
@ -1111,7 +1111,7 @@ def admin():
@app.route('/admin/user/edit/<user_username>', methods=['GET', 'POST'])
@app.route('/admin/user/edit', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_edituser(user_username=None):
if request.method == 'GET':
if not user_username:
@ -1150,11 +1150,12 @@ def admin_edituser(user_username=None):
@app.route('/admin/manageuser', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_manageuser():
if request.method == 'GET':
roles = Role.query.all()
users = User.query.order_by(User.username).all()
return render_template('admin_manageuser.html', users=users)
return render_template('admin_manageuser.html', users=users, roles=roles)
if request.method == 'POST':
#
@ -1197,19 +1198,31 @@ def admin_manageuser():
else:
return make_response(jsonify( { 'status': 'error', 'msg': 'Cannot revoke user privilege.' } ), 500)
elif jdata['action'] == 'set_admin':
elif jdata['action'] == 'update_user_role':
username = data['username']
role_name = data['role_name']
if username == current_user.username:
return make_response(jsonify( { 'status': 'error', 'msg': 'You cannot change you own admin rights.' } ), 400)
is_admin = data['is_admin']
return make_response(jsonify( { 'status': 'error', 'msg': 'You cannot change you own roles.' } ), 400)
user = User.query.filter(User.username==username).first()
if not user:
return make_response(jsonify( { 'status': 'error', 'msg': 'User does not exist.' } ), 404)
if user.role.name == 'Administrator' and current_user.role.name != 'Administrator':
return make_response(jsonify( { 'status': 'error', 'msg': 'You do not have permission to change Administrator users role.' } ), 400)
if role_name == 'Administrator' and current_user.role.name != 'Administrator':
return make_response(jsonify( { 'status': 'error', 'msg': 'You do not have permission to promote a user to Administrator role.' } ), 400)
user = User(username=username)
result = user.set_admin(is_admin)
if result:
history = History(msg='Change user role of {0}'.format(username), created_by=current_user.username)
result = user.set_role(role_name)
if result['status']:
history = History(msg='Change user role of {0} to {1}'.format(username, role_name), created_by=current_user.username)
history.add()
return make_response(jsonify( { 'status': 'ok', 'msg': 'Changed user role successfully.' } ), 200)
else:
return make_response(jsonify( { 'status': 'error', 'msg': 'Cannot change user role.' } ), 500)
return make_response(jsonify( { 'status': 'error', 'msg': 'Cannot change user role. {0}'.format(result['msg']) } ), 500)
else:
return make_response(jsonify( { 'status': 'error', 'msg': 'Action not supported.' } ), 400)
except:
@ -1220,7 +1233,7 @@ def admin_manageuser():
@app.route('/admin/account/edit/<account_name>', methods=['GET', 'POST'])
@app.route('/admin/account/edit', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_editaccount(account_name=None):
users = User.query.all()
@ -1274,7 +1287,7 @@ def admin_editaccount(account_name=None):
@app.route('/admin/manageaccount', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_manageaccount():
if request.method == 'GET':
accounts = Account.query.order_by(Account.name).all()
@ -1308,7 +1321,7 @@ def admin_manageaccount():
@app.route('/admin/history', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_history():
if request.method == 'POST':
h = History()
@ -1328,7 +1341,7 @@ def admin_history():
@app.route('/admin/setting/basic', methods=['GET'])
@login_required
@admin_role_required
@operator_role_required
def admin_setting_basic():
if request.method == 'GET':
settings = Setting.query.filter(Setting.view=='basic').all()
@ -1337,7 +1350,7 @@ def admin_setting_basic():
@app.route('/admin/setting/basic/<path:setting>/edit', methods=['POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_setting_basic_edit(setting):
jdata = request.json
new_value = jdata['value']
@ -1351,7 +1364,7 @@ def admin_setting_basic_edit(setting):
@app.route('/admin/setting/basic/<path:setting>/toggle', methods=['POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_setting_basic_toggle(setting):
result = Setting().toggle(setting)
if (result):
@ -1383,7 +1396,7 @@ def admin_setting_pdns():
@app.route('/admin/setting/dns-records', methods=['GET', 'POST'])
@login_required
@admin_role_required
@operator_role_required
def admin_setting_records():
if request.method == 'GET':
f_records = literal_eval(Setting().get('forward_records_allow_edit'))
@ -1438,6 +1451,7 @@ def admin_setting_authentication():
Setting().set('ldap_filter_username', request.form.get('ldap_filter_username'))
Setting().set('ldap_sg_enabled', True if request.form.get('ldap_sg_enabled')=='ON' else False)
Setting().set('ldap_admin_group', request.form.get('ldap_admin_group'))
Setting().set('ldap_operator_group', request.form.get('ldap_operator_group'))
Setting().set('ldap_user_group', request.form.get('ldap_user_group'))
result = {'status': True, 'msg': 'Saved successfully'}
elif conf_type == 'google':

View File

@ -0,0 +1,58 @@
"""Adding Operator Role
Revision ID: 4a666113c7bb
Revises: 1274ed462010
Create Date: 2018-08-30 13:28:06.836208
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4a666113c7bb'
down_revision = '1274ed462010'
branch_labels = None
depends_on = None
def update_data():
setting_table = sa.sql.table('setting',
sa.sql.column('id', sa.Integer),
sa.sql.column('name', sa.String),
sa.sql.column('value', sa.String),
sa.sql.column('view', sa.String)
)
# add ldap_operator_group setting
op.bulk_insert(setting_table,
[
{'id': 44, 'name': 'ldap_operator_group', 'value': '', 'view': 'authentication'},
]
)
role_table = sa.sql.table('role',
sa.sql.column('id', sa.Integer),
sa.sql.column('name', sa.String),
sa.sql.column('description', sa.String)
)
# add new role
op.bulk_insert(role_table,
[
{'id': 3, 'name': 'Operator', 'description': 'Operator'}
]
)
def upgrade():
update_data()
def downgrade():
# remove user Operator role
op.execute("UPDATE user SET role_id = 2 WHERE role_id=3")
op.execute("DELETE FROM role WHERE name = 'Operator'")
# delete ldap setting
op.execute("DELETE FROM setting WHERE name = 'ldap_operator_group'")