diff --git a/admin/docker/Dockerfile b/admin/docker/Dockerfile
index 0d13ce9..8fd020b 100644
--- a/admin/docker/Dockerfile
+++ b/admin/docker/Dockerfile
@@ -14,6 +14,8 @@ RUN apk del .build_deps
RUN apk add --no-cache curl py3-yaml yarn libpq openssl
+RUN wget -O /usr/lib/python3.8/site-packages/diceware/wordlists/wordlist_cat_ascii.txt https://raw.githubusercontent.com/1ma/diceware-cat/master/cat-wordlist-ascii.txt
+
# SSH configuration
ARG SSH_ROOT_PWD
RUN apk add openssh
diff --git a/admin/docker/requirements.pip3 b/admin/docker/requirements.pip3
index b693745..07e82d0 100644
--- a/admin/docker/requirements.pip3
+++ b/admin/docker/requirements.pip3
@@ -17,7 +17,7 @@ zope.interface==5.1.0
psycopg2==2.8.6
Flask-SocketIO==2.8.6
mysql-connector-python==8.0.25
-
+diceware==0.9.6
#Flask-SocketIO==2.8.6
#gevent==1.4.0
diff --git a/admin/src/admin/lib/admin.py b/admin/src/admin/lib/admin.py
index 1af82e7..475822b 100644
--- a/admin/src/admin/lib/admin.py
+++ b/admin/src/admin/lib/admin.py
@@ -13,9 +13,18 @@ from pprint import pprint
import traceback, os, json
from time import sleep
+import diceware
+options = diceware.handle_options(None)
+options.wordlist = 'cat_ascii'
+options.num = 3
+
+
+
from flask_socketio import SocketIO, emit, join_room, leave_room, \
close_room, rooms, disconnect, send
socketio = SocketIO(app)
+from ..views.Socketio import socketio
+# socketio = SocketIO(app)
class Admin():
def __init__(self):
@@ -407,6 +416,7 @@ class Admin():
def upload_json(self,data):
groups=[]
+ log.warning('Processing uploaded groups...')
for g in data['data']['groups']:
# for m in data['data']['d_members']:
@@ -418,8 +428,12 @@ class Admin():
"description": g['description']})
self.external['groups']=groups
+ log.warning('Processing uploaded users...')
users=[]
+ total=len(data['data']['users'])
+ i=1
for u in data['data']['users']:
+ log.warning('Processing ('+str(i)+'/'+str(total)+') uploaded user: '+u['primaryEmail'].split('@')[0])
# data['provider']
users.append({'provider':'external',
'id':u['id'],
@@ -427,8 +441,14 @@ class Admin():
'first': u['name']['givenName'],
'last': u['name']['familyName'],
'username': u['primaryEmail'].split('@')[0],
- 'groups':[u['orgUnitPath'][1:]], ## WARNING: Removing the first
- 'roles':[]})
+ 'groups':[u['orgUnitPath']], ## WARNING: Removing the first
+ 'roles':[],
+ 'password':diceware.get_passphrase(options=options)})
+ socketio.emit('update',
+ json.dumps({'status':True,'item':'user','action':'delete','itemdata':''}),
+ namespace='/isard-sso-admin/sio',
+ room='admin')
+ i=i+1
self.external['users']=users
## Add groups to users (now they only have their orgUnitPath)
@@ -443,23 +463,84 @@ class Admin():
pprint(ids)
log.warning('Starting sync to keycloak')
self.sync_to_keycloak()
- log.warning('Starting sync to moodle')
- self.sync_to_moodle()
- log.warning('Starting sync to nextcloud')
- self.sync_to_nextcloud()
- log.warning('All syncs finished')
+ # log.warning('Starting sync to moodle')
+ # self.sync_to_moodle()
+ # log.warning('Starting sync to nextcloud')
+ # self.sync_to_nextcloud()
+ # log.warning('All syncs finished')
- def sync_to_keycloak(self):
+ def sync_to_keycloak(self): ### This one works from the external, moodle and nextcloud from the internal
+ groups=[]
for u in self.external['users']:
- log.info('Creating user: '+u['username'])
- self.keycloak.add_user_with_groups_and_role(u['username'],u['first'],u['last'],u['email'],'1Provaprovaprova',u['roles'],u['groups'])
- # self.keycloak.add_user(u['username'],u['first'],u['last'],u['email'],'1Provaprovaprova',group=u['groups'][0])
+ groups=groups+u['groups']
+ groups=list(dict.fromkeys(groups))
+
+ total=len(groups)
+ i=0
+ for g in groups:
+ i=i+1
+ # print('ADDING FULL PATH: '+str(g))
+ log.warning(' KEYCLOAK GROUPS: Adding group ('+str(i)+'/'+str(total)+'): '+g)
+ self.keycloak.add_group_tree(g)
+
+ total=len(self.external['users'])
+ index=0
+ for u in self.external['users']:
+ index=index+1
+ # Add user
+ log.warning(' KEYCLOAK USERS: Adding user ('+str(index)+'/'+str(total)+'): '+u['username'])
+ uid=self.keycloak.add_user(u['username'],u['first'],u['last'],u['email'],u['password'])
+
+ # Add user to role and group rolename
+ if len(u['roles']) != 0:
+ log.warning(' KEYCLOAK USERS: Assign user '+u['username']+' with initial pwd '+ u['password']+' to role '+u['roles'][0])
+ self.keycloak.assign_realm_roles(uid,u['roles'][0])
+ gid=self.keycloak.get_group(path='/'+u['roles'][0])['id']
+ self.keycloak.group_user_add(uid,gid)
+ # Add user to groups
+ for g in u['groups']:
+ parts=g.split('/')
+ sub=''
+ if len(parts)==0:
+ log.warning(' KEYCLOAK USERS: Skip assign user '+u['username']+' to any group as des not have one')
+ continue # NO GROUP
+ for i in range(1,len(parts)):
+ sub=sub+'/'+parts[i]
+
+ if sub=='/': continue # User with no path
+ log.warning(' KEYCLOAK USERS: Assign user '+u['username']+' to group '+ str(sub))
+ gid=self.keycloak.get_group(path=sub)['id']
+ self.keycloak.group_user_add(uid,gid)
+ self.resync_data()
+
+ def sync_to_moodle(self): # works from the internal (keycloak)
+ groups=[]
+ for u in self.internal['users']:
+ groups=groups+u['keycloak_groups']
+ groups=list(dict.fromkeys(groups))
+
+ pprint(groups)
+ total=len(groups)
+ i=0
+ for g in groups:
+ parts=g.split('/')
+ subpath=''
+ for i in range(1,len(parts)):
+ try:
+ log.warning(' MOODLE GROUPS: Adding group as cohort ('+str(i)+'/'+str(total)+'): '+subpath)
+ subpath=subpath+'/'+parts[i]
+ self.moodle.add_system_cohort(subpath)
+ except:
+ log.error('probably exists')
+ i=i+1
+ # print('ADDING FULL PATH: '+str(g))
+ return
+
- def sync_to_moodle(self):
for u in self.internal['users']:
if not u['moodle']:
log.info('Creating moodle user: '+u['username'])
- self.moodle.create_user(u['email'],u['username'],'-1Provaprovaprova',u['first'],u['last'])
+ self.moodle.create_user(u['email'],u['username'],u['password'],u['first'],u['last'])
def sync_to_nextcloud(self):
for u in self.internal['users']:
@@ -467,7 +548,7 @@ class Admin():
log.info('Creating nextcloud user: '+u['username'])
group=u['keycloak_groups'][0] if len(u['keycloak_groups']) else False
try:
- self.nextcloud.add_user(u['username'],'-1Provaprovaprova',1000,group,u['email'],u['first']+' '+u['last'])
+ self.nextcloud.add_user(u['username'],u['password'],2000000000000,group,u['email'],u['first']+' '+u['last'])
except ProviderItemExists:
log.info('User '+u['username']+' already exists. Skipping...')
continue
@@ -476,12 +557,15 @@ class Admin():
#
Las contraseñas deben tener al menos 1 dígito(s).
Las contraseñas deben tener al menos 1 mayúscula(s).
Las contraseñas deben tener al menos 1 caracter(es) no alfanumérico(s) como *,-,
def delete_keycloak_users(self):
+ total=len(self.internal['users'])
+ i=0
for u in self.internal['users']:
+ i=i+1
if not u['keycloak']: continue
# Do not remove admin users!!! What to do with managers???
if 'admin' in u['roles']: continue
- if 'manager' in u['roles']: continue
- log.info('Removing keycloak user: '+u['username'])
+ # if 'manager' in u['roles']: continue
+ log.info(' KEYCLOAK USERS: Removing user ('+str(i)+'/'+str(total)+'): '+u['username'])
try:
self.keycloak.delete_user(u['id'])
socketio.emit('update',
@@ -489,8 +573,7 @@ class Admin():
namespace='/isard-sso-admin/sio',
room='admin')
except:
- log.error(traceback.format_exc())
- log.warning('Could not remove user: '+u['username'])
+ log.warning(' KEYCLOAK USERS: Could not remove user: '+u['username'] +'. Probably already not exists.')
def delete_nextcloud_users(self):
for u in self.internal['users']:
diff --git a/admin/src/admin/lib/keycloak_client.py b/admin/src/admin/lib/keycloak_client.py
index fa1fae3..1847af5 100644
--- a/admin/src/admin/lib/keycloak_client.py
+++ b/admin/src/admin/lib/keycloak_client.py
@@ -84,6 +84,35 @@ class KeycloakClient():
left join keycloak_role as r on r.id = rm.role_id
group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
order by u.username"""
+
+ # q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, ua.value as quota, g.id, g.path, g.name,
+ # --,json_agg(g."name") as group, json_agg(g_parent."name") as group_parent1, json_agg(g_parent2."name") as group_parent2
+ # --,json_agg(r.name) as role
+ # from user_entity as u
+ # left join user_attribute as ua on ua.user_id=u.id and ua.name = 'quota'
+ # left join user_group_membership as ugm on ugm.user_id = u.id
+ # left join keycloak_group as g on g.id = ugm.group_id
+ # --left join keycloak_group as g_parent on g.parent_group = g_parent.id
+ # --left join keycloak_group as g_parent2 on g_parent.parent_group = g_parent2.id
+ # left join user_role_mapping as rm on rm.user_id = u.id
+ # left join keycloak_role as r on r.id = rm.role_id
+ # --group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
+ # order by u.username"""
+
+ # q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, ua.value as quota
+ # ,json_agg(g."name") as group_name,json_agg(g."id") as group_id,json_agg(g."path") as group_path
+ # ,json_agg(g_parent."name") as group_parent1, json_agg(g_parent2."name") as group_parent2
+ # ,json_agg(r.name) as role
+ # from user_entity as u
+ # left join user_attribute as ua on ua.user_id=u.id and ua.name = 'quota'
+ # left join user_group_membership as ugm on ugm.user_id = u.id
+ # left join keycloak_group as g on g.id = ugm.group_id
+ # left join keycloak_group as g_parent on g.parent_group = g_parent.id
+ # left join keycloak_group as g_parent2 on g_parent.parent_group = g_parent2.id
+ # left join user_role_mapping as rm on rm.user_id = u.id
+ # left join keycloak_role as r on r.id = rm.role_id
+ # group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
+ # order by u.username"""
(headers,users)=self.keycloak_pg.select_with_headers(q)
users_with_lists = [list(l[:-4])+([[]] if l[-4] == [None] else [list(set(l[-4]))]) +\
@@ -108,7 +137,7 @@ class KeycloakClient():
# user['roles']= [r['name'] for r in self.keycloak_admin.get_realm_roles_of_user(user_id=user['id'])]
# return users
- def add_user(self,username,first,last,email,password,group=False):
+ def add_user(self,username,first,last,email,password,group=False,temporary=True):
# Returns user id
self.connect()
username=username.lower()
@@ -120,7 +149,7 @@ class KeycloakClient():
"lastName": last,
"credentials":[{"type":"password",
"value":password,
- "temporary":False}]})
+ "temporary":temporary}]})
except:
log.error(traceback.format_exc())
@@ -134,6 +163,13 @@ class KeycloakClient():
self.keycloak_admin.group_user_add(uid,gid)
return uid
+ def update_user_pwd(self,user_id='61092e24-cd67-4b50-baf9-b60e01f12bff',payload={},temporary=True):
+ payload={"credentials":[{"type":"password",
+ "value":'pepito',
+ "temporary":temporary}]}
+ self.connect()
+ self.keycloak_admin.update_user( user_id, payload)
+
def remove_user_group(self,user_id,group_id):
self.connect()
pass
@@ -196,15 +232,31 @@ class KeycloakClient():
def add_group_tree(self,path):
parts=path.split('/')
- sub=''
- for i in range(1,len(parts+1)):
+ parent_path=None
+ for i in range(1,len(parts)):
+ # print('Adding group name '+parts[i]+' with parent path '+str(parent_path))
try:
- if i == 1: parent_id=self.add_group(parts[i])
+ self.add_group(parts[i],parent_path,skip_exists=True)
except:
- # Main already exists?? What a fail!
- parent_id=self.get_group(parent_id)['id']
+ if parent_path==None:
+ parent_path='/'+parts[i]
+ else:
+ parent_path=self.get_group(parent_path)['path']
+ parent_path=parent_path+parts[i]
continue
- self.add_group(parts[i],parent_id)
+
+ if parent_path==None:
+ parent_path='/'+parts[i]
+ else:
+ parent_path=parent_path+parts[i]
+
+ # try:
+ # if i == 1: parent_id=self.add_group(parts[i])
+ # except:
+ # # Main already exists?? What a fail!
+ # parent_id=self.get_group(parent_id)['id']
+ # continue
+ # self.add_group(parts[i],parent_id)
def add_user_with_groups_and_role(self,username,first,last,email,password,role,groups):
## Add user
@@ -232,9 +284,12 @@ class KeycloakClient():
thepath='/'+parts[i]
else:
thepath=parent_path+'/'+parts[i]
- if thepath=='/': continue
+ if thepath=='/':
+ print('Not adding the user '+username+' to any group as does not have any...')
+ continue
gid=self.get_group(path=thepath)['id']
+ print('Adding '+username+' with uuid: '+uid+' to group '+g+' with uuid: '+gid)
self.keycloak_admin.group_user_add(uid,gid)
@@ -242,7 +297,7 @@ class KeycloakClient():
parent_path=parent_path+'/'+parts[i]
- self.group_user_add(uid,gid)
+ # self.group_user_add(uid,gid)
## ROLES
diff --git a/admin/src/admin/lib/moodle.py b/admin/src/admin/lib/moodle.py
index 34d7d6d..5816ad2 100644
--- a/admin/src/admin/lib/moodle.py
+++ b/admin/src/admin/lib/moodle.py
@@ -130,6 +130,18 @@ class Moodle():
cohort = self.call('core_cohort_create_cohorts', cohorts=data)
return cohort
+ # def add_users_to_cohort(self,users,cohort):
+ # criteria = [{'key': key, 'value': value}]
+ # user = self.call('core_cohort_add_cohort_members', criteria=criteria)
+ # return user
+
+ # def add_users_to_cohort(self,userid,cohortid):
+ # members=[{'cohorttype':{'type':'system','value':cohortid},
+ # 'usertype':{'type':'id','value':userid}}]
+ # criteria = [{'key': key, 'value': value}]
+ # user = self.call('core_cohort_add_cohort_members', criteria=criteria)
+ # return user
+
def get_cohort_members(self, cohort_id):
members = self.call('core_cohort_get_cohort_members', cohortids=[cohort_id])[0]['userids']
return members
diff --git a/admin/src/admin/static/js/external.js b/admin/src/admin/static/js/external.js
index 482c888..932d44b 100644
--- a/admin/src/admin/static/js/external.js
+++ b/admin/src/admin/static/js/external.js
@@ -15,7 +15,7 @@ $(document).ready(function() {
$('.btn-sync').on('click', function () {
ids={}
$.each(users_table.rows().data(),function(key, value){
- ids[value['id']]=value['role']
+ ids[value['id']]=value['roles']
});
console.log(ids)
$.ajax({
@@ -35,7 +35,16 @@ $(document).ready(function() {
}
});
});
-
+
+ $('.btn-download').on('click', function () {
+
+ data=users_table.rows().data()
+ csv_data='TYPE,EXTID,EMAIL,FIRST,LSAT,USERNAME,GROUPS,ROLE,PASSWORD'+ '\r\n'
+ csv_data=csv_data+convertToCSV(data)
+ console.log(csv_data)
+ exportCSVFile(csv_data, 'users_data')
+ })
+
$("#modalImport #send").on('click', function(e){
console.log(users_table.rows().data())
var form = $('#modalImportForm');
@@ -143,6 +152,7 @@ $(document).ready(function() {
{ "data": "email", "width": "10px"},
{ "data": "groups", "width": "10px"},
{ "data": "roles", "width": "10px"},
+ { "data": "password", "width": "10px"},
],
"order": [[3, 'asc']],
"columnDefs": [ {
@@ -227,4 +237,47 @@ function populate_path(){
$.each(items, function(key, value) {
$(".populate").append('');
})
+}
+
+function convertToCSV(objArray) {
+ var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
+ var str = '';
+
+ for (var i = 0; i < array.length; i++) {
+ var line = '';
+ for (var index in array[i]) {
+ if (line != '') line += ','
+
+ if (Array.isArray(array[i][index])){
+ line += '"'+array[i][index]+'"'
+ }else{
+ line += array[i][index];
+ }
+ }
+
+ str += line + '\r\n';
+ }
+
+ return str;
+}
+
+function exportCSVFile(csv, fileTitle) {
+ var exportedFilenmae = fileTitle + '.csv' || 'export.csv';
+
+ var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
+ if (navigator.msSaveBlob) { // IE 10+
+ navigator.msSaveBlob(blob, exportedFilenmae);
+ } else {
+ var link = document.createElement("a");
+ if (link.download !== undefined) { // feature detection
+ // Browsers that support HTML5 download attribute
+ var url = URL.createObjectURL(blob);
+ link.setAttribute("href", url);
+ link.setAttribute("download", exportedFilenmae);
+ link.style.visibility = 'hidden';
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ }
+ }
}
\ No newline at end of file
diff --git a/admin/src/admin/static/templates/base.html b/admin/src/admin/static/templates/base.html
index 30ac39c..2a2558c 100644
--- a/admin/src/admin/static/templates/base.html
+++ b/admin/src/admin/static/templates/base.html
@@ -111,6 +111,7 @@
+
diff --git a/admin/src/admin/static/templates/pages/external.html b/admin/src/admin/static/templates/pages/external.html
index a40b828..71d8129 100644
--- a/admin/src/admin/static/templates/pages/external.html
+++ b/admin/src/admin/static/templates/pages/external.html
@@ -47,6 +47,7 @@
email |
groups |
roles |
+ password |
diff --git a/admin/src/admin/static/templates/pages/users.html b/admin/src/admin/static/templates/pages/users.html
index 85f1fcf..0fd62fb 100644
--- a/admin/src/admin/static/templates/pages/users.html
+++ b/admin/src/admin/static/templates/pages/users.html
@@ -75,5 +75,4 @@
-
{% endblock %}
diff --git a/admin/src/admin/views/Socketio.py b/admin/src/admin/views/Socketio.py
index d70bdc2..b2b968d 100644
--- a/admin/src/admin/views/Socketio.py
+++ b/admin/src/admin/views/Socketio.py
@@ -1,7 +1,10 @@
from flask_socketio import SocketIO, emit, join_room, leave_room, \
close_room, rooms, disconnect, send
from admin import app
+import json
+
socketio = SocketIO(app)
+# from ...start import socketio
@socketio.on('connect', namespace='/isard-sso-admin/sio')
def socketio_connect():
diff --git a/admin/src/claus.py b/admin/src/claus.py
new file mode 100644
index 0000000..cb330ba
--- /dev/null
+++ b/admin/src/claus.py
@@ -0,0 +1,5 @@
+import diceware
+options = diceware.handle_options(None)
+options.wordlist = 'cat_ascii'
+options.num = 3
+print(diceware.get_passphrase(options=options))
diff --git a/admin/src/postgres.py b/admin/src/postgres.py
new file mode 100644
index 0000000..ebc8989
--- /dev/null
+++ b/admin/src/postgres.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# coding=utf-8
+import time
+from datetime import datetime, timedelta
+import pprint
+
+import logging as log
+import traceback
+import yaml, json
+
+import psycopg2
+
+class Postgres():
+
+ def __init__(self,host,database,user,password):
+ self.conn = psycopg2.connect(
+ host=host,
+ database=database,
+ user=user,
+ password=password)
+
+
+ # def __del__(self):
+ # self.cur.close()
+ # self.conn.close()
+
+ def select(self,sql):
+ self.cur = self.conn.cursor()
+ self.cur.execute(sql)
+ data=self.cur.fetchall()
+ self.cur.close()
+ return data
+
+ def update(self,sql):
+ self.cur = self.conn.cursor()
+ self.cur.execute(sql)
+ self.conn.commit()
+ self.cur.close()
+ # return self.cur.fetchall()
+
+ def select_with_headers(self,sql):
+ self.cur = self.conn.cursor()
+ self.cur.execute(sql)
+ data=self.cur.fetchall()
+ fields = [a.name for a in self.cur.description]
+ self.cur.close()
+ return (fields,data)
+
+ # def update_moodle_saml_plugin(self):
+ # plugin[('idpmetadata', 'NrtA5ynG0htowP3SXw7dBJRIAMxn-1PwuuXwOwNhlRwMIICmzCCAYMCBgF5jb0RCTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwNTIxMDcwMjI4WhcNMzEwNTIxMDcwNDA4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCI8xh/C0+frz3kgWiUbziTDls71R2YiXLSVE+bw7gbEgZUGCLhoEI679azMtIxmnzM/snIX+yTb12+XoYkgbiLTMPQfnH+Kiab6g3HL3KPfhqS+yWkFxOoCp6Ibmp7yPlVWuHH+MBfO8OBr/r8Ao7heFbuzjiLd1KG67rcoaxfDgMuBoEomg1bgEjFgHaQIrSC6OZzH0h987/arqufZXeXlfyiqScMPUi+u5IpDWSwz06UKP0k8mxzNSlpZ93CKOUSsV0SMLxqg7FQ3SGiOk577bGW9o9BDTkkmSo3Up6smc0LzwvvUwuNd0B1irGkWZFQN9OXJnJYf1InEebIMtmPAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADM34+qEGeBQ22luphVTuVJtGxcbxLx7DfsT0QfJD/OuxTTbNAa1VRyarb5juIAkqdj4y2quZna9ZXLecVo4RkwpzPoKoAkYA8b+kHnWqEwJi9iPrDvKb+GR0bBkLPN49YxIZ8IdKX/PRa3yuLHe+loiNsCaS/2ZK2KO46COsqU4QX1iVhF9kWphNLybjNAX45B6cJLsa1g0vXLdm3kv3SB4I2fErFVaOoDtFIjttoYlXdpUiThkPXBfr7N67P3dZHaS4tjJh+IZ8I6TINpcsH8dBkUhzYEIPHCePwSiC1w6WDBLNDuKt1mj1CZrLq+1x+Yhrs+QNRheEKGi89HZ8N0=urn:oasis:names:tc:SAML:2.0:nameid-format:persistenturn:oasis:names:tc:SAML:2.0:nameid-format:transienturn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedurn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress')]
+ # pg_update = """UPDATE mdl_config_plugins set title = %s where plugin = auth_saml2 and name ="""
+ # cursor.execute(pg_update, (title, bookid))
+ # connection.commit()
+ # count = cursor.rowcount
+ # print(count, "Successfully Updated!")
\ No newline at end of file
diff --git a/admin/src/reset_pwds.py b/admin/src/reset_pwds.py
new file mode 100644
index 0000000..03b35a1
--- /dev/null
+++ b/admin/src/reset_pwds.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+import time ,os
+from datetime import datetime, timedelta
+
+import logging as log
+import traceback
+import yaml, json
+from pprint import pprint
+
+from jinja2 import Environment, FileSystemLoader
+
+from keycloak import KeycloakAdmin
+from postgres import Postgres
+
+import diceware
+options = diceware.handle_options(None)
+options.wordlist = 'cat_ascii'
+options.num = 3
+
+class KeycloakClient():
+ """https://www.keycloak.org/docs-api/13.0/rest-api/index.html
+ https://github.com/marcospereirampj/python-keycloak
+ https://gist.github.com/kaqfa/99829941121188d7cef8271f93f52f1f
+ """
+ def __init__(self,
+ url="http://isard-sso-keycloak:8080/auth/",
+ username=os.environ['KEYCLOAK_USER'],
+ password=os.environ['KEYCLOAK_PASSWORD'],
+ realm='master',
+ verify=True):
+ self.url=url
+ self.username=username
+ self.password=password
+ self.realm=realm
+ self.verify=verify
+
+ self.keycloak_pg=Postgres('isard-apps-postgresql','keycloak',os.environ['KEYCLOAK_DB_USER'],os.environ['KEYCLOAK_DB_PASSWORD'])
+
+ def connect(self):
+ self.keycloak_admin = KeycloakAdmin(server_url=self.url,
+ username=self.username,
+ password=self.password,
+ realm_name=self.realm,
+ verify=self.verify)
+
+
+ def update_pwds(self):
+ self.get_users()
+
+ def get_users(self):
+ self.connect()
+ users=self.get_users_with_groups_and_roles()
+ userupdate=[]
+ for u in users:
+ if u['username'] not in ['admin'] and not u['username'].startswith('system_'):
+ print('Generating password for user '+u['username'])
+ userupdate.append({'id':u['id'],
+ 'username':u['username'],
+ 'password': 'pepito'})
+ # diceware.get_passphrase(options=options)})
+ with open("user_temp_passwd.csv"),"w") as csv:
+ csv.write(self.parse_idp_metadata())
+ for u in userupdate:
+ print('Updating keycloak password for user '+u['username'])
+ self.update_user_pwd(u['id'],u['password'])
+
+ def update_user_pwd(self,user_id,password,temporary=True):
+ payload={"credentials":[{"type":"password",
+ "value":password,
+ "temporary":temporary}]}
+ self.connect()
+ self.keycloak_admin.update_user( user_id, payload)
+
+
+ def get_users_with_groups_and_roles(self):
+ q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, ua.value as quota
+ ,json_agg(g."name") as group, json_agg(g_parent."name") as group_parent1, json_agg(g_parent2."name") as group_parent2
+ ,json_agg(r.name) as role
+ from user_entity as u
+ left join user_attribute as ua on ua.user_id=u.id and ua.name = 'quota'
+ left join user_group_membership as ugm on ugm.user_id = u.id
+ left join keycloak_group as g on g.id = ugm.group_id
+ left join keycloak_group as g_parent on g.parent_group = g_parent.id
+ left join keycloak_group as g_parent2 on g_parent.parent_group = g_parent2.id
+ left join user_role_mapping as rm on rm.user_id = u.id
+ left join keycloak_role as r on r.id = rm.role_id
+ group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
+ order by u.username"""
+
+ # q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, ua.value as quota, g.id, g.path, g.name,
+ # --,json_agg(g."name") as group, json_agg(g_parent."name") as group_parent1, json_agg(g_parent2."name") as group_parent2
+ # --,json_agg(r.name) as role
+ # from user_entity as u
+ # left join user_attribute as ua on ua.user_id=u.id and ua.name = 'quota'
+ # left join user_group_membership as ugm on ugm.user_id = u.id
+ # left join keycloak_group as g on g.id = ugm.group_id
+ # --left join keycloak_group as g_parent on g.parent_group = g_parent.id
+ # --left join keycloak_group as g_parent2 on g_parent.parent_group = g_parent2.id
+ # left join user_role_mapping as rm on rm.user_id = u.id
+ # left join keycloak_role as r on r.id = rm.role_id
+ # --group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
+ # order by u.username"""
+
+ # q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, ua.value as quota
+ # ,json_agg(g."name") as group_name,json_agg(g."id") as group_id,json_agg(g."path") as group_path
+ # ,json_agg(g_parent."name") as group_parent1, json_agg(g_parent2."name") as group_parent2
+ # ,json_agg(r.name) as role
+ # from user_entity as u
+ # left join user_attribute as ua on ua.user_id=u.id and ua.name = 'quota'
+ # left join user_group_membership as ugm on ugm.user_id = u.id
+ # left join keycloak_group as g on g.id = ugm.group_id
+ # left join keycloak_group as g_parent on g.parent_group = g_parent.id
+ # left join keycloak_group as g_parent2 on g_parent.parent_group = g_parent2.id
+ # left join user_role_mapping as rm on rm.user_id = u.id
+ # left join keycloak_role as r on r.id = rm.role_id
+ # group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
+ # order by u.username"""
+ (headers,users)=self.keycloak_pg.select_with_headers(q)
+
+ users_with_lists = [list(l[:-4])+([[]] if l[-4] == [None] else [list(set(l[-4]))]) +\
+ ([[]] if l[-3] == [None] else [list(set(l[-3]))]) +\
+ ([[]] if l[-3] == [None] else [list(set(l[-2]))]) +\
+ ([[]] if l[-1] == [None] else [list(set(l[-1]))]) for l in users]
+
+ users_with_lists = [list(l[:-4])+([[]] if l[-4] == [None] else [list(set(l[-4]))]) +\
+ ([[]] if l[-3] == [None] else [list(set(l[-3]))]) +\
+ ([[]] if l[-3] == [None] else [list(set(l[-2]))]) +\
+ ([[]] if l[-1] == [None] else [list(set(l[-1]))]) for l in users_with_lists]
+
+ list_dict_users = [dict(zip(headers, r)) for r in users_with_lists]
+ return list_dict_users
+
+k=KeycloakClient()
+k.update_pwds()
\ No newline at end of file
diff --git a/admin/src/start.py b/admin/src/start.py
index 7e56420..6f18bcb 100644
--- a/admin/src/start.py
+++ b/admin/src/start.py
@@ -8,21 +8,22 @@ from flask_socketio import SocketIO, emit, join_room, leave_room, \
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.init_app(app, cors_allowed_origins="*")
+
+from admin.views.Socketio import *
+# 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
+# @socketio.on('disconnect', namespace='/isard-sso-admin/sio')
+# def socketio_domains_disconnect():
+# None
if __name__ == '__main__':
socketio.run(app,host='0.0.0.0', port=9000, debug=False, cors_allowed_origins="*") #, logger=logger, engineio_logger=engineio_logger)