parent child groups
parent
defd0b51fe
commit
c02ef731af
|
@ -16,4 +16,11 @@ zope.event==4.4
|
|||
zope.interface==5.1.0
|
||||
psycopg2==2.8.6
|
||||
Flask-SocketIO==2.8.6
|
||||
mysql-connector-python==8.0.25
|
||||
mysql-connector-python==8.0.25
|
||||
|
||||
|
||||
#Flask-SocketIO==2.8.6
|
||||
#gevent==1.4.0
|
||||
#greenlet==0.4.15
|
||||
python-engineio==3.8.1
|
||||
python-socketio==4.1.0
|
|
@ -32,6 +32,8 @@ Postup()
|
|||
from admin.lib.admin import Admin
|
||||
app.admin=Admin()
|
||||
|
||||
app.ready=False
|
||||
|
||||
'''
|
||||
Debug should be removed on production!
|
||||
'''
|
||||
|
@ -84,3 +86,4 @@ from .views import AvatarViews
|
|||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,19 @@ class Admin():
|
|||
sleep(2)
|
||||
log.warning('Keycloak connected.')
|
||||
|
||||
# try:
|
||||
# self.keycloak.add_group('parent1')
|
||||
# except:
|
||||
# pass
|
||||
# try:
|
||||
# self.keycloak.add_group('child1','/parent1')
|
||||
# except:
|
||||
# pass
|
||||
# try:
|
||||
# self.keycloak.add_group('child2','/parent1')
|
||||
# except:
|
||||
# pass
|
||||
|
||||
ready=False
|
||||
while not ready:
|
||||
try:
|
||||
|
@ -306,6 +319,7 @@ class Admin():
|
|||
theuser={**moodle_exists[0], **theuser}
|
||||
theuser['moodle']=True
|
||||
theuser['moodle_groups']=moodle_exists[0]['groups']
|
||||
theuser['moodle_id']=moodle_exists[0]['id']
|
||||
else:
|
||||
theuser['moodle']=False
|
||||
theuser['moodle_groups']=[]
|
||||
|
@ -315,6 +329,7 @@ class Admin():
|
|||
theuser={**nextcloud_exists[0], **theuser}
|
||||
theuser['nextcloud']=True
|
||||
theuser['nextcloud_groups']=nextcloud_exists[0]['groups']
|
||||
theuser['nextcloud_id']=nextcloud_exists[0]['id']
|
||||
else:
|
||||
theuser['nextcloud']=False
|
||||
theuser['nextcloud_groups']=[]
|
||||
|
@ -406,15 +421,18 @@ class Admin():
|
|||
for g in data['data']['groups']:
|
||||
# for m in data['data']['d_members']:
|
||||
|
||||
groups.append({'provider':data['provider'],
|
||||
# data['provider']
|
||||
groups.append({'provider':'external',
|
||||
"id": g['id'],
|
||||
"mailid": g['email'].split('@')[0],
|
||||
"name": g['name'],
|
||||
"description": g['description']})
|
||||
self.external['groups']=groups
|
||||
|
||||
users=[]
|
||||
for u in data['data']['users']:
|
||||
users.append({'provider':data['provider'],
|
||||
# data['provider']
|
||||
users.append({'provider':'external',
|
||||
'id':u['id'],
|
||||
'email': u['primaryEmail'],
|
||||
'first': u['name']['givenName'],
|
||||
|
@ -424,6 +442,12 @@ class Admin():
|
|||
'roles':[]})
|
||||
self.external['users']=users
|
||||
|
||||
## Add groups to users (now they only have their orgUnitPath)
|
||||
for g in self.external['groups']:
|
||||
for useringroup in data['data']['d_members'][g['mailid']]:
|
||||
for u in self.external['users']:
|
||||
if u['id'] == useringroup['id']:
|
||||
u['groups']=u['groups']+[g['name']]
|
||||
return True
|
||||
|
||||
def sync_external(self):
|
||||
|
@ -468,7 +492,41 @@ class Admin():
|
|||
log.error(traceback.format_exc())
|
||||
log.warning('Could not remove user: '+u['username'])
|
||||
|
||||
def delete_keycloak_groups(self):
|
||||
def delete_nextcloud_users(self):
|
||||
for u in self.internal['users']:
|
||||
if u['nextcloud'] and not u['keycloak']:
|
||||
if u['roles'] and 'admin' in u['roles']: continue
|
||||
log.info('Removing nextcloud user: '+u['username'])
|
||||
try:
|
||||
self.nextcloud.delete_user(u['nextcloud_id'])
|
||||
socketio.emit('update',
|
||||
json.dumps({'status':True,'item':'user','action':'delete','itemdata':u}),
|
||||
namespace='/isard-sso-admin/sio',
|
||||
room='admin')
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
log.warning('Could not remove user: '+u['username'])
|
||||
|
||||
def delete_moodle_users(self):
|
||||
userids=[]
|
||||
usernames=[]
|
||||
for u in self.internal['users']:
|
||||
if u['moodle'] and not u['keycloak']:
|
||||
userids.append(u['moodle_id'])
|
||||
usernames.append(u['username'])
|
||||
|
||||
log.warning('Removing moodle users: '+','.join(usernames))
|
||||
try:
|
||||
self.moodle.delete_users(userids)
|
||||
socketio.emit('update',
|
||||
json.dumps({'status':True,'item':'user','action':'delete','itemdata':u}),
|
||||
namespace='/isard-sso-admin/sio',
|
||||
room='admin')
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
log.warning('Could not remove users: '+','.join(usernames))
|
||||
|
||||
def delete_moodle_groups(self):
|
||||
for g in self.internal['groups']:
|
||||
if not g['keycloak']: continue
|
||||
# Do not remove admin group. It should not exist in keycloak, only in nextcloud
|
||||
|
@ -478,4 +536,11 @@ class Admin():
|
|||
self.keycloak.delete_group(g['id'])
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
log.warning('Could not remove group: '+g['name'])
|
||||
log.warning('Could not remove group: '+g['name'])
|
||||
|
||||
def external_roleassign(self,data):
|
||||
for newuserid in data['ids']:
|
||||
for externaluser in self.external['users']:
|
||||
if externaluser['id'] == newuserid:
|
||||
externaluser['roles']=[data['action']]
|
||||
return True
|
|
@ -164,6 +164,10 @@ class KeycloakClient():
|
|||
|
||||
def add_group(self,name,parent=None):
|
||||
self.connect()
|
||||
if parent is not None: parent=self.get_group(parent)['id']
|
||||
print(name)
|
||||
print(parent)
|
||||
print('DONE')
|
||||
return self.keycloak_admin.create_group({"name":name}, parent=parent)
|
||||
|
||||
def delete_group(self,group_id):
|
||||
|
|
|
@ -2,7 +2,7 @@ from requests import get, post
|
|||
from admin import app
|
||||
|
||||
import logging as log
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
from .postgres import Postgres
|
||||
|
||||
|
@ -72,6 +72,14 @@ class Moodle():
|
|||
user = self.call('core_user_create_users', users=data)
|
||||
return user
|
||||
|
||||
def delete_user(self, user_id):
|
||||
user = self.call('core_user_delete_users', userids=[user_id])
|
||||
return user
|
||||
|
||||
def delete_users(self, userids):
|
||||
user = self.call('core_user_delete_users', userids=userids)
|
||||
return user
|
||||
|
||||
def get_user_by(self, key, value):
|
||||
criteria = [{'key': key, 'value': value}]
|
||||
user = self.call('core_user_get_users', criteria=criteria)
|
||||
|
|
|
@ -128,7 +128,7 @@ class Nextcloud():
|
|||
|
||||
def add_user(self,userid,userpassword,quota=False,group=False,email='',displayname=''):
|
||||
data={'userid':userid,'password':userpassword,'quota':quota,'groups[]':group,'email':email,'displayname':displayname}
|
||||
if not group: del data['group']
|
||||
if not group: del data['groups[]']
|
||||
if not quota: del data['quota']
|
||||
# if group:
|
||||
# data={'userid':userid,'password':userpassword,'quota':quota,'groups[]':group,'email':email,'displayname':displayname}
|
||||
|
|
|
@ -54,6 +54,60 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
$('#action_role').on('change', function () {
|
||||
action=$(this).val();
|
||||
names=''
|
||||
ids=[]
|
||||
|
||||
if(users_table.rows('.active').data().length){
|
||||
$.each(users_table.rows('.active').data(),function(key, value){
|
||||
names+=value['name']+'\n';
|
||||
ids.push(value['id']);
|
||||
});
|
||||
var text = "You are about to assign role "+action+" these users:\n\n "+names
|
||||
}else{
|
||||
$.each(users_table.rows({filter: 'applied'}).data(),function(key, value){
|
||||
ids.push(value['id']);
|
||||
});
|
||||
var text = "You are about to assign role "+action+" "+users_table.rows({filter: 'applied'}).data().length+" users!\n All the users in list!"
|
||||
}
|
||||
new PNotify({
|
||||
title: 'Role assignment!',
|
||||
text: 'You will asign the role '+action,
|
||||
hide: false,
|
||||
opacity: 0.9,
|
||||
confirm: {
|
||||
confirm: true
|
||||
},
|
||||
buttons: {
|
||||
closer: false,
|
||||
sticker: false
|
||||
},
|
||||
history: {
|
||||
history: false
|
||||
},
|
||||
addclass: 'pnotify-center'
|
||||
}).get().on('pnotify.confirm', function() {
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
url:"/isard-sso-admin/external/roles",
|
||||
data: JSON.stringify({'ids':ids,'action':action}),
|
||||
success: function(data)
|
||||
{
|
||||
console.log('SUCCESS')
|
||||
users_table.ajax.reload();
|
||||
groups_table.ajax.reload();
|
||||
},
|
||||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
}
|
||||
});
|
||||
}).on('pnotify.cancel', function() {
|
||||
$('#action_role option[value="none"]').prop("selected",true);
|
||||
});
|
||||
} );
|
||||
|
||||
//DataTable Main renderer
|
||||
var users_table = $('#users').DataTable({
|
||||
"ajax": {
|
||||
|
@ -74,8 +128,8 @@ $(document).ready(function() {
|
|||
"width": "10px",
|
||||
"defaultContent": '<button class="btn btn-xs btn-info" type="button" data-placement="top" ><i class="fa fa-plus"></i></button>'
|
||||
},
|
||||
{ "data": "provider", "width": "10px" },
|
||||
{ "data": "id", "width": "10px" },
|
||||
// { "data": "provider", "width": "10px" },
|
||||
// { "data": "id", "width": "10px" },
|
||||
{ "data": "username", "width": "10px"},
|
||||
{ "data": "first", "width": "10px"},
|
||||
{ "data": "last", "width": "10px"},
|
||||
|
@ -84,9 +138,15 @@ $(document).ready(function() {
|
|||
{ "data": "roles", "width": "10px"},
|
||||
],
|
||||
"order": [[3, 'asc']],
|
||||
"columnDefs": [ ]
|
||||
"columnDefs": [ {
|
||||
"targets": 5,
|
||||
"render": function ( data, type, full, meta ) {
|
||||
return "<li>" + full.groups.join("</li><li>") + "</li>"
|
||||
}}
|
||||
]
|
||||
} );
|
||||
|
||||
|
||||
|
||||
var groups_table = $('#groups').DataTable({
|
||||
"ajax": {
|
||||
"url": "/isard-sso-admin/external_groups_list",
|
||||
|
@ -106,8 +166,8 @@ $(document).ready(function() {
|
|||
"width": "10px",
|
||||
"defaultContent": '<button class="btn btn-xs btn-info" type="button" data-placement="top" ><i class="fa fa-plus"></i></button>'
|
||||
},
|
||||
{ "data": "id", "width": "10px" },
|
||||
{ "data": "provider", "width": "10px" },
|
||||
// { "data": "id", "width": "10px" },
|
||||
// { "data": "provider", "width": "10px" },
|
||||
{ "data": "name", "width": "10px" },
|
||||
{ "data": "description", "width": "10px"},
|
||||
],
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// SocketIO
|
||||
socket = io.connect(location.protocol+'//' + document.domain + ':' + location.port+'/isard-sso-admin/sio');
|
||||
|
||||
socket = io.connect(location.protocol+'//' + document.domain +'/isard-sso-admin/sio');
|
||||
console.log(location.protocol+'//' + document.domain +'/isard-sso-admin/sio')
|
||||
socket.on('connect', function() {
|
||||
connection_done();
|
||||
// connection_done();
|
||||
console.log('Listening status socket');
|
||||
});
|
||||
|
||||
socket.on('connect_error', function(data) {
|
||||
connection_lost();
|
||||
// connection_lost();
|
||||
});
|
||||
|
||||
socket.on('update', function(data) {
|
||||
|
|
|
@ -112,6 +112,41 @@ $(document).ready(function() {
|
|||
});
|
||||
});
|
||||
|
||||
$('.btn-delete_nextcloud').on('click', function () {
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url:"/isard-sso-admin/users/nextcloud",
|
||||
success: function(data)
|
||||
{
|
||||
console.log('SUCCESS')
|
||||
// $("#modalImport").modal('hide');
|
||||
// users_table.ajax.reload();
|
||||
// groups_table.ajax.reload();
|
||||
},
|
||||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.btn-delete_moodle').on('click', function () {
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
url:"/isard-sso-admin/users/moodle",
|
||||
success: function(data)
|
||||
{
|
||||
console.log('SUCCESS')
|
||||
// $("#modalImport").modal('hide');
|
||||
// users_table.ajax.reload();
|
||||
// groups_table.ajax.reload();
|
||||
},
|
||||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
}
|
||||
});
|
||||
});
|
||||
$('.btn-sync_to_moodle').on('click', function () {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
|
|
|
@ -14,6 +14,19 @@
|
|||
<div class="x_title">
|
||||
<h3><i class="fa fa-desktop"></i> External</h3>
|
||||
<ul class="nav navbar-right panel_toolbox">
|
||||
<li>
|
||||
<div class="item form-group">
|
||||
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="action_role">Assign role: <span class="required">*</span></label>
|
||||
<div class="col-md-6 col-sm-6 col-xs-12">
|
||||
<select id="action_role" name="action_role" class="form-control action" required>
|
||||
<option value=''>Select role</option>
|
||||
<option value='manager'>Manager</option>
|
||||
<option value='teacher'>Teacher</option>
|
||||
<option value='student'>Student</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="btn-sync"><span style="color: #5499c7; "><i class="fa fa-rocket"></i> Sync to system</span></a>
|
||||
<a class="btn-upload"><span style="color: #5499c7; "><i class="fa fa-upload"></i> Upload</span></a>
|
||||
|
@ -28,8 +41,6 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Provider</th>
|
||||
<th>Id</th>
|
||||
<th>Username</th>
|
||||
<th>First</th>
|
||||
<th>Last</th>
|
||||
|
@ -48,8 +59,6 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Id</th>
|
||||
<th>Provider</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
<input id="id" hidden/>
|
||||
-->
|
||||
|
||||
<div class="item form-group">
|
||||
<!-- <div class="item form-group">
|
||||
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="provider">Provider name: <span class="required">*</span></label>
|
||||
<div class="col-md-6 col-sm-6 col-xs-12">
|
||||
<input id="provider" name="provider" placeholder="" type="text" style="width:100%">
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="item form-group">
|
||||
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="format">Format: <span class="required">*</span></label>
|
||||
<div class="col-md-6 col-sm-6 col-xs-12">
|
||||
|
@ -46,7 +46,7 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="x_panela" id="bulkusers-quota" style="padding: 5px;">
|
||||
<!-- <div class="x_panela" id="bulkusers-quota" style="padding: 5px;">
|
||||
<p style="font-size: 18px;margin-bottom:0px;">Map User keys</p>
|
||||
|
||||
<div class="item form-group">
|
||||
|
@ -114,7 +114,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
<button class="btn btn-danger btn-xs btn-delete_keycloak">
|
||||
<i class="fa fa-trash"></i> Delete all keycloak
|
||||
</button>
|
||||
<button class="btn btn-danger btn-xs btn-delete_nextcloud">
|
||||
<i class="fa fa-trash"></i> Delete missing keycloak in nextcloud
|
||||
</button>
|
||||
<button class="btn btn-danger btn-xs btn-delete_moodle">
|
||||
<i class="fa fa-trash"></i> Delete missing keycloak in moodle
|
||||
</button>
|
||||
<table id="users" class="table" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -68,5 +74,6 @@
|
|||
<!-- Switchery -->
|
||||
<script src="/isard-sso-admin/vendors/switchery/dist/switchery.min.js"></script>
|
||||
<!-- Desktops sse & modals -->
|
||||
<script src="/isard-sso-admin/static/js/users.js"></script>
|
||||
<script src="/isard-sso-admin/static/js/users.js"></script>
|
||||
<script src="/isard-sso-admin/static/js/status_socket.js"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -23,6 +23,10 @@ def users(provider=False):
|
|||
if request.method == 'DELETE':
|
||||
if provider == 'keycloak':
|
||||
return json.dumps(app.admin.delete_keycloak_users()), 200, {'Content-Type': 'application/json'}
|
||||
if provider == 'nextcloud':
|
||||
return json.dumps(app.admin.delete_nextcloud_users()), 200, {'Content-Type': 'application/json'}
|
||||
if provider == 'moodle':
|
||||
return json.dumps(app.admin.delete_moodle_users()), 200, {'Content-Type': 'application/json'}
|
||||
if request.method == 'POST':
|
||||
if provider == 'moodle':
|
||||
return json.dumps(app.admin.sync_to_moodle()), 200, {'Content-Type': 'application/json'}
|
||||
|
@ -79,4 +83,10 @@ def external_users_list():
|
|||
@app.route('/isard-sso-admin/external_groups_list')
|
||||
# @login_required
|
||||
def external_groups_list():
|
||||
return json.dumps(app.admin.get_external_groups()), 200, {'Content-Type': 'application/json'}
|
||||
return json.dumps(app.admin.get_external_groups()), 200, {'Content-Type': 'application/json'}
|
||||
|
||||
@app.route('/isard-sso-admin/external/roles', methods=['PUT'])
|
||||
# @login_required
|
||||
def external_roles():
|
||||
if request.method == 'PUT':
|
||||
return json.dumps(app.admin.external_roleassign(request.get_json(force=True))), 200, {'Content-Type': 'application/json'}
|
|
@ -0,0 +1,16 @@
|
|||
from flask_socketio import SocketIO, emit, join_room, leave_room, \
|
||||
close_room, rooms, disconnect, send
|
||||
from admin import app
|
||||
socketio = SocketIO(app)
|
||||
|
||||
@socketio.on('connect', namespace='/isard-sso-admin/sio')
|
||||
def socketio_connect():
|
||||
join_room('admin')
|
||||
socketio.emit('update',
|
||||
json.dumps('Joined'),
|
||||
namespace='/isard-sso-admin/sio',
|
||||
room='admin')
|
||||
|
||||
@socketio.on('disconnect', namespace='/isard-sso-admin/sio')
|
||||
def socketio_domains_disconnect():
|
||||
None
|
|
@ -134,6 +134,7 @@ class MoodleSaml():
|
|||
'duallogin': '1',
|
||||
'idpattr': 'username',
|
||||
'autocreate': '1',
|
||||
'anyauth': '1',
|
||||
'saml_role_siteadmin_map': 'admin',
|
||||
'saml_role_coursecreator_map': 'teacher',
|
||||
'saml_role_manager_map': 'manager',
|
||||
|
|
|
@ -3,8 +3,26 @@
|
|||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
|
||||
|
||||
from flask_socketio import SocketIO, emit, join_room, leave_room, \
|
||||
close_room, rooms, disconnect, send
|
||||
import json
|
||||
from admin import app
|
||||
|
||||
socketio = SocketIO(app)
|
||||
socketio.init_app(app, cors_allowed_origins="*")
|
||||
|
||||
# from .admin.views.Socketio import *
|
||||
@socketio.on('connect', namespace='/isard-sso-admin/sio')
|
||||
def socketio_connect():
|
||||
join_room('admin')
|
||||
socketio.emit('update',
|
||||
json.dumps('Joined'),
|
||||
namespace='/isard-sso-admin/sio',
|
||||
room='admin')
|
||||
|
||||
@socketio.on('disconnect', namespace='/isard-sso-admin/sio')
|
||||
def socketio_domains_disconnect():
|
||||
None
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=9000, debug=False) #, logger=logger, engineio_logger=engineio_logger)
|
||||
socketio.run(app,host='0.0.0.0', port=9000, debug=False, cors_allowed_origins="*") #, logger=logger, engineio_logger=engineio_logger)
|
||||
|
|
|
@ -34,6 +34,9 @@ frontend website
|
|||
http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\ if { ssl_fc_has_crt }
|
||||
bind :443 ssl crt /certs/chain.pem
|
||||
|
||||
acl is_upgrade hdr(Connection) -i upgrade
|
||||
acl is_websocket hdr(Upgrade) -i websocket
|
||||
|
||||
acl is_nextcloud hdr_beg(host) nextcloud.
|
||||
acl is_moodle hdr_beg(host) moodle.
|
||||
acl is_jitsi hdr_beg(host) jitsi.
|
||||
|
@ -51,11 +54,13 @@ frontend website
|
|||
use_backend be_oof if is_oof
|
||||
use_backend be_wp if is_wp
|
||||
use_backend be_etherpad if is_pad
|
||||
use_backend be_admin if is_sso { path_beg /socket.io }
|
||||
use_backend be_adminer if is_sso { path_beg /isard-sso-adminer }
|
||||
use_backend be_admin if is_sso { path_beg /isard-sso-admin }
|
||||
use_backend be_sso if is_sso
|
||||
use_backend be_ipa if is_ipa
|
||||
use_backend be_api if is_api
|
||||
|
||||
|
||||
# default_backend be_sso
|
||||
|
||||
|
|
Loading…
Reference in New Issue