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)