progress
parent
cf50f2b839
commit
7f786e6a0f
|
@ -6,12 +6,17 @@ from .nextcloud import Nextcloud
|
|||
import logging as log
|
||||
from pprint import pprint
|
||||
|
||||
from .nextcloud_exc import *
|
||||
|
||||
class Admin():
|
||||
def __init__(self):
|
||||
self.keycloak=Keycloak(verify=app.config['VERIFY'])
|
||||
self.moodle=Moodle(verify=app.config['VERIFY'])
|
||||
self.nextcloud=Nextcloud(verify=app.config['VERIFY'])
|
||||
|
||||
# self.internal={'users':self.get_mix_users(),
|
||||
# 'groups':self.get_mix_groups(),
|
||||
# 'roles':[]}
|
||||
self.external={'users':[],
|
||||
'groups':[],
|
||||
'roles':[]}
|
||||
|
@ -21,18 +26,24 @@ class Admin():
|
|||
# pprint(self.get_nextcloud_users())
|
||||
|
||||
def get_moodle_users(self):
|
||||
users = self.moodle.get_users_with_groups_and_roles()
|
||||
#self.moodle.get_user_by('email','%%')['users']
|
||||
return [{"id":u['id'],
|
||||
"username":u['username'],
|
||||
"first": u['firstname'],
|
||||
"last": u['lastname'],
|
||||
"email": u['email'],
|
||||
"groups": u['groups'],
|
||||
"roles": u['roles']}
|
||||
for u in users]
|
||||
return self.moodle.get_users_with_groups_and_roles()
|
||||
|
||||
## TOO SLOW. Not used.
|
||||
# def get_moodle_users(self):
|
||||
# log.warning('Loading moodle users... can take a long time...')
|
||||
# users = self.moodle.get_users_with_groups_and_roles()
|
||||
# #self.moodle.get_user_by('email','%%')['users']
|
||||
# return [{"id":u['id'],
|
||||
# "username":u['username'],
|
||||
# "first": u['firstname'],
|
||||
# "last": u['lastname'],
|
||||
# "email": u['email'],
|
||||
# "groups": u['groups'],
|
||||
# "roles": u['roles']}
|
||||
# for u in users]
|
||||
|
||||
def get_keycloak_users(self):
|
||||
log.warning('Loading keycloak users... can take a long time...')
|
||||
users = self.keycloak.get_users_with_groups_and_roles()
|
||||
return [{"id":u['id'],
|
||||
"username":u['username'],
|
||||
|
@ -44,6 +55,7 @@ class Admin():
|
|||
for u in users]
|
||||
|
||||
def get_nextcloud_users(self):
|
||||
log.warning('Loading nextcloud users... can take a long time...')
|
||||
users = self.nextcloud.get_users_list()
|
||||
users_list=[]
|
||||
for user in users:
|
||||
|
@ -57,10 +69,14 @@ class Admin():
|
|||
"roles": []})
|
||||
return users_list
|
||||
|
||||
# def get_ram_users(self):
|
||||
# return self.internal['users']
|
||||
|
||||
def get_mix_users(self):
|
||||
kusers=self.get_keycloak_users()
|
||||
musers=self.get_moodle_users()
|
||||
nusers=self.get_nextcloud_users()
|
||||
# nusers=self.get_nextcloud_users()
|
||||
nusers=[]
|
||||
|
||||
kusers_usernames=[u['username'] for u in kusers]
|
||||
musers_usernames=[u['username'] for u in musers]
|
||||
|
@ -107,15 +123,21 @@ class Admin():
|
|||
return self.keycloak.get_roles()
|
||||
|
||||
def get_keycloak_groups(self):
|
||||
log.warning('Loading keycloak groups... can take a long time...')
|
||||
return self.keycloak.get_groups()
|
||||
|
||||
def get_moodle_groups(self):
|
||||
log.warning('Loading moodle groups... can take a long time...')
|
||||
return self.moodle.get_cohorts()
|
||||
|
||||
def get_nextcloud_groups(self):
|
||||
log.warning('Loading nextcloud groups... can take a long time...')
|
||||
return self.nextcloud.get_groups_list()
|
||||
|
||||
def get_groups(self):
|
||||
# def get_ram_groups(self):
|
||||
# return self.internal['groups']
|
||||
|
||||
def get_mix_groups(self):
|
||||
kgroups=self.get_keycloak_groups()
|
||||
mgroups=self.get_moodle_groups()
|
||||
ngroups=self.get_nextcloud_groups()
|
||||
|
@ -198,8 +220,29 @@ class Admin():
|
|||
|
||||
return True
|
||||
|
||||
def sync_external(self):
|
||||
for u in self.external['users']:
|
||||
log.error('Creating user: '+u['username'])
|
||||
self.keycloak.add_user(u['username'],u['first'],u['last'],u['email'],'1Provaprovaprova',group=u['groups'][0])
|
||||
|
||||
# with open(os.path.join(app.root_path, "../custom/jsons/google_all_imported_espinalt.json"),"r") as crt:
|
||||
# pprint(data)
|
||||
|
||||
def sync_to_moodle(self):
|
||||
users=self.get_mix_users()
|
||||
for u in users:
|
||||
if not u['moodle']:
|
||||
log.error('Creating moodle user: '+u['username'])
|
||||
self.moodle.create_user(u['email'],u['username'],'-1Provaprovaprova',u['first'],u['last'])
|
||||
|
||||
def sync_to_nextcloud(self):
|
||||
users=self.get_mix_users()
|
||||
for u in users:
|
||||
if not u['nextcloud']:
|
||||
log.error('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'])
|
||||
except ProviderItemExists:
|
||||
log.error('User '+u['username']+' already exists. Skipping...')
|
||||
continue
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
# <div>Las contraseñas deben tener al menos 1 dígito(s).</div><div>Las contraseñas deben tener al menos 1 mayúscula(s).</div><div>Las contraseñas deben tener al menos 1 caracter(es) no alfanumérico(s) como *,-,
|
||||
|
|
|
@ -37,6 +37,8 @@ class Keycloak():
|
|||
realm_name=self.realm,
|
||||
verify=self.verify)
|
||||
|
||||
# keycloak_admin = KeycloakAdmin(server_url="http://isard-sso-keycloak:8080/auth/",username="admin",password="keycloakkeycloak",realm_name="master",verify=False)
|
||||
|
||||
######## Example create group and subgroup
|
||||
|
||||
# try:
|
||||
|
@ -65,26 +67,74 @@ class Keycloak():
|
|||
self.connect()
|
||||
return self.keycloak_admin.get_users({})
|
||||
|
||||
# q = """select 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.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
|
||||
# order by u.username"""
|
||||
# cur.execute(q)
|
||||
# users = cur.fetchall()
|
||||
# fields = [a.name for a in cur.description]
|
||||
# cur.close()
|
||||
# conn.close()
|
||||
|
||||
|
||||
# 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(fields, r)) for r in users_with_lists]
|
||||
|
||||
## Too slow
|
||||
def get_users_with_groups_and_roles(self):
|
||||
self.connect()
|
||||
users=self.keycloak_admin.get_users({})
|
||||
for user in users:
|
||||
log.error(user)
|
||||
user['groups']=[g['path'] for g in self.keycloak_admin.get_user_groups(user_id=user['id'])]
|
||||
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):
|
||||
def add_user(self,username,first,last,email,password,group=False):
|
||||
# Returns user id
|
||||
log.error('Creating group: '+str(group))
|
||||
self.connect()
|
||||
return self.keycloak_admin.create_user({"email": email,
|
||||
"username": username,
|
||||
"enabled": True,
|
||||
"firstName": first,
|
||||
"lastName": last,
|
||||
"credentials":[{"type":"password",
|
||||
"value":password,
|
||||
"temporary":False}]})
|
||||
username=username.lower()
|
||||
try:
|
||||
uid=self.keycloak_admin.create_user({"email": email,
|
||||
"username": username,
|
||||
"enabled": True,
|
||||
"firstName": first,
|
||||
"lastName": last,
|
||||
"credentials":[{"type":"password",
|
||||
"value":password,
|
||||
"temporary":False}]})
|
||||
except:
|
||||
uid=self.keycloak_admin.get_user_id(username)
|
||||
log.error(uid)
|
||||
if group:
|
||||
try:
|
||||
gid=self.keycloak_admin.get_group_by_path(path='/'+group,search_in_subgroups=False)['id']
|
||||
log.error('group created with gid: '+str(gid))
|
||||
except:
|
||||
self.keycloak_admin.create_group({"name":group})
|
||||
gid=self.keycloak_admin.get_group_by_path('/'+group)['id']
|
||||
log.error(gid)
|
||||
self.keycloak_admin.group_user_add(uid,gid)
|
||||
|
||||
|
||||
def add_user_role(self,client_id,user_id,role_id,role_name):
|
||||
self.connect()
|
||||
|
|
|
@ -3,6 +3,9 @@ from admin import app
|
|||
|
||||
import logging as log
|
||||
|
||||
|
||||
from .postgres import Postgres
|
||||
|
||||
# Module variables to connect to moodle api
|
||||
|
||||
class Moodle():
|
||||
|
@ -20,7 +23,10 @@ class Moodle():
|
|||
self.url = url
|
||||
self.endpoint = endpoint
|
||||
self.verify=verify
|
||||
|
||||
|
||||
self.pg=Postgres('isard-apps-postgresql','moodle',app.config['MOODLE_POSTGRES_USER'],app.config['MOODLE_POSTGRES_PASSWORD'])
|
||||
|
||||
|
||||
def rest_api_parameters(self, in_args, prefix='', out_dict=None):
|
||||
"""Transform dictionary/array structure to a flat dictionary, with key names
|
||||
defining the structure.
|
||||
|
@ -70,14 +76,27 @@ class Moodle():
|
|||
criteria = [{'key': key, 'value': value}]
|
||||
user = self.call('core_user_get_users', criteria=criteria)
|
||||
return user
|
||||
|
||||
|
||||
def get_users_with_groups_and_roles(self):
|
||||
users=self.get_user_by('email','%%')['users']
|
||||
for user in users:
|
||||
user['groups']=[c['name'] for c in self.get_user_cohorts(user['id'])]
|
||||
user['roles']=[]
|
||||
log.error(users)
|
||||
return users
|
||||
q = """select u.id as id, username, firstname as first, lastname as last, email, json_agg(h.name) as groups, json_agg(r.shortname) as roles
|
||||
from mdl_user as u
|
||||
LEFT JOIN mdl_cohort_members AS hm on hm.id = u.id
|
||||
left join mdl_cohort AS h ON h.id = hm.cohortid
|
||||
left join mdl_role_assignments AS ra ON ra.id = u.id
|
||||
left join mdl_role as r on r.id = ra.roleid
|
||||
group by u.id , username, first, last, email"""
|
||||
(headers,users)=self.pg.select_with_headers(q)
|
||||
users_with_lists = [list(l[:-2])+([[]] if l[-2] == [None] else [list(set(l[-2]))]) + ([[]] if l[-1] == [None] else [list(set(l[-1]))]) for l in users]
|
||||
list_dict_users = [dict(zip(headers, r)) for r in users_with_lists]
|
||||
return list_dict_users
|
||||
|
||||
## NOT USED. Too slow
|
||||
# def get_users_with_groups_and_roles(self):
|
||||
# users=self.get_user_by('email','%%')['users']
|
||||
# for user in users:
|
||||
# user['groups']=[c['name'] for c in self.get_user_cohorts(user['id'])]
|
||||
# user['roles']=[]
|
||||
# return users
|
||||
|
||||
def enroll_user_to_course(self, user_id, course_id, role_id=5):
|
||||
# 5 is student
|
||||
|
|
|
@ -76,6 +76,27 @@ class Nextcloud():
|
|||
raise
|
||||
# 100 - successful
|
||||
|
||||
# q = """select u.uid as username, adn.value as displayname, ade.value as email, json_agg(gg.displayname) as admin_groups,json_agg(g.displayname) as groups
|
||||
# from oc_users as u
|
||||
# left join oc_group_user as gu on gu.uid = u.uid
|
||||
# left join oc_groups as g on gu.gid = g.gid
|
||||
# left join oc_group_admin as ga on ga.uid = u.uid
|
||||
# left join oc_groups as gg on gg.gid = ga.gid
|
||||
# left join oc_accounts_data as adn on adn.uid = u.uid and adn.name = 'displayname'
|
||||
# left join oc_accounts_data as ade on ade.uid = u.uid and ade.name = 'email'
|
||||
# group by u.uid, adn.value, ade.value"""
|
||||
# cur.execute(q)
|
||||
# users = cur.fetchall()
|
||||
# fields = [a.name for a in cur.description]
|
||||
# cur.close()
|
||||
# conn.close()
|
||||
|
||||
|
||||
# users_with_lists = [list(l[:-2])+([[]] if l[-2] == [None] else [list(set(l[-2]))]) + ([[]] if l[-1] == [None] else [list(set(l[-1]))]) for l in users]
|
||||
# users_with_lists = [list(l[:-2])+([[]] if l[-2] == [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(fields, r)) for r in users_with_lists]
|
||||
|
||||
### Too slow...
|
||||
def get_users_list(self):
|
||||
url = self.apiurl + "users?format=json"
|
||||
try:
|
||||
|
@ -87,8 +108,11 @@ class Nextcloud():
|
|||
log.error(traceback.format_exc())
|
||||
raise
|
||||
|
||||
def add_user(self,userid,userpassword,quota,group='',email='',displayname=''):
|
||||
data={'userid':userid,'password':userpassword,'quota':quota,'groups[]':group,'email':email,'displayname':displayname}
|
||||
def add_user(self,userid,userpassword,quota,group=False,email='',displayname=''):
|
||||
if group:
|
||||
data={'userid':userid,'password':userpassword,'quota':quota,'groups[]':group,'email':email,'displayname':displayname}
|
||||
else:
|
||||
data={'userid':userid,'password':userpassword,'quota':quota,'email':email,'displayname':displayname}
|
||||
url = self.apiurl + "users?format=json"
|
||||
headers = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
|
@ -98,7 +122,9 @@ class Nextcloud():
|
|||
result = json.loads(self._request('POST',url,data=data,headers=headers))
|
||||
if result['ocs']['meta']['statuscode'] == 100: return True
|
||||
if result['ocs']['meta']['statuscode'] == 102: raise ProviderItemExists
|
||||
if result['ocs']['meta']['statuscode'] == 104: raise ProviderGroupNotExists
|
||||
if result['ocs']['meta']['statuscode'] == 104:
|
||||
self.add_group(group)
|
||||
# raise ProviderGroupNotExists
|
||||
log.error('Get Nextcloud provider user add error: '+str(result))
|
||||
raise ProviderOpError
|
||||
except:
|
||||
|
|
|
@ -34,6 +34,12 @@ class Postgres():
|
|||
self.conn.commit()
|
||||
# return self.cur.fetchall()
|
||||
|
||||
def select_with_headers(self,sql):
|
||||
self.cur.execute(sql)
|
||||
data=self.cur.fetchall()
|
||||
fields = [a.name for a in self.cur.description]
|
||||
return (fields,data)
|
||||
|
||||
# def update_moodle_saml_plugin(self):
|
||||
# plugin[('idpmetadata', '<md:EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Name="urn:keycloak"><md:EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://sso.'+app.config['DOMAIN']+'/auth/realms/master"><md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo><ds:KeyName>NrtA5ynG0htowP3SXw7dBJRIAMxn-1PwuuXwOwNhlRw</ds:KeyName><ds:X509Data><ds:X509Certificate>MIICmzCCAYMCBgF5jb0RCTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMjEwNTIxMDcwMjI4WhcNMzEwNTIxMDcwNDA4WjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCI8xh/C0+frz3kgWiUbziTDls71R2YiXLSVE+bw7gbEgZUGCLhoEI679azMtIxmnzM/snIX+yTb12+XoYkgbiLTMPQfnH+Kiab6g3HL3KPfhqS+yWkFxOoCp6Ibmp7yPlVWuHH+MBfO8OBr/r8Ao7heFbuzjiLd1KG67rcoaxfDgMuBoEomg1bgEjFgHaQIrSC6OZzH0h987/arqufZXeXlfyiqScMPUi+u5IpDWSwz06UKP0k8mxzNSlpZ93CKOUSsV0SMLxqg7FQ3SGiOk577bGW9o9BDTkkmSo3Up6smc0LzwvvUwuNd0B1irGkWZFQN9OXJnJYf1InEebIMtmPAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADM34+qEGeBQ22luphVTuVJtGxcbxLx7DfsT0QfJD/OuxTTbNAa1VRyarb5juIAkqdj4y2quZna9ZXLecVo4RkwpzPoKoAkYA8b+kHnWqEwJi9iPrDvKb+GR0bBkLPN49YxIZ8IdKX/PRa3yuLHe+loiNsCaS/2ZK2KO46COsqU4QX1iVhF9kWphNLybjNAX45B6cJLsa1g0vXLdm3kv3SB4I2fErFVaOoDtFIjttoYlXdpUiThkPXBfr7N67P3dZHaS4tjJh+IZ8I6TINpcsH8dBkUhzYEIPHCePwSiC1w6WDBLNDuKt1mj1CZrLq+1x+Yhrs+QNRheEKGi89HZ8N0=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml/resolve" index="0"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.santantoni.duckdns.org/auth/realms/master/protocol/saml"/></md:IDPSSODescriptor></md:EntityDescriptor></md:EntitiesDescriptor>')]
|
||||
# pg_update = """UPDATE mdl_config_plugins set title = %s where plugin = auth_saml2 and name ="""
|
||||
|
|
|
@ -12,6 +12,24 @@ $(document).ready(function() {
|
|||
$('#modalImportForm')[0].reset();
|
||||
});
|
||||
|
||||
$('.btn-sync').on('click', function () {
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
url:"/isard-sso-admin/external",
|
||||
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...')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#modalImport #send").on('click', function(e){
|
||||
var form = $('#modalImportForm');
|
||||
form.parsley().validate();
|
||||
|
|
|
@ -14,6 +14,42 @@ $(document).ready(function() {
|
|||
$('#modalAdd').parsley();
|
||||
});
|
||||
|
||||
$('.btn-sync_to_moodle').on('click', function () {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
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_nextcloud').on('click', function () {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
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...')
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//DataTable Main renderer
|
||||
var table = $('#users').DataTable({
|
||||
"ajax": {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<h3><i class="fa fa-desktop"></i> External</h3>
|
||||
<ul class="nav navbar-right panel_toolbox">
|
||||
<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>
|
||||
<a class="btn-download"><span style="color: #5499c7; "><i class="fa fa-download"></i> Download</span></a>
|
||||
</li>
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
<ul class="nav navbar-right panel_toolbox">
|
||||
<li>
|
||||
<a class="btn-new"><span style="color: #5499c7; "><i class="fa fa-plus"></i> Add new</span></a>
|
||||
<a class="btn-sync_to_moodle"><span style="color: #5499c7; "><i class="fa fa-rocket"></i> Sync to Moodle</span></a>
|
||||
<a class="btn-sync_to_nextcloud"><span style="color: #5499c7; "><i class="fa fa-rocket"></i> Sync to Nextcloud</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
|
|
|
@ -11,9 +11,15 @@ from flask import render_template, Response, request, redirect, url_for, jsonify
|
|||
|
||||
from pprint import pprint
|
||||
|
||||
@app.route('/isard-sso-admin/users')
|
||||
@app.route('/isard-sso-admin/users', methods=['GET'])
|
||||
@app.route('/isard-sso-admin/users/<provider>', methods=['POST', 'PUT', 'GET'])
|
||||
# @login_required
|
||||
def users():
|
||||
def users(provider=False):
|
||||
if request.method == 'POST':
|
||||
if provider == 'moodle':
|
||||
return json.dumps(app.admin.sync_to_moodle()), 200, {'Content-Type': 'application/json'}
|
||||
if provider == 'nextcloud':
|
||||
return json.dumps(app.admin.sync_to_nextcloud()), 200, {'Content-Type': 'application/json'}
|
||||
return render_template('pages/users.html', title="Users", nav="Users")
|
||||
|
||||
@app.route('/isard-sso-admin/users_list')
|
||||
|
@ -41,14 +47,16 @@ def groups():
|
|||
@app.route('/isard-sso-admin/groups_list')
|
||||
# @login_required
|
||||
def groups_list():
|
||||
return json.dumps(app.admin.get_groups()), 200, {'Content-Type': 'application/json'}
|
||||
return json.dumps(app.admin.get_mix_groups()), 200, {'Content-Type': 'application/json'}
|
||||
|
||||
|
||||
@app.route('/isard-sso-admin/external', methods=['POST', 'GET'])
|
||||
@app.route('/isard-sso-admin/external', methods=['POST', 'PUT', 'GET'])
|
||||
# @login_required
|
||||
def external():
|
||||
if request.method == 'POST':
|
||||
return json.dumps(app.admin.upload_json(request.get_json(force=True))), 200, {'Content-Type': 'application/json'}
|
||||
if request.method == 'PUT':
|
||||
return json.dumps(app.admin.sync_external()), 200, {'Content-Type': 'application/json'}
|
||||
return render_template('pages/external.html', title="External", nav="External")
|
||||
|
||||
@app.route('/isard-sso-admin/external_users_list')
|
||||
|
|
|
@ -23,7 +23,7 @@ class MoodleSaml():
|
|||
ready=False
|
||||
while not ready:
|
||||
try:
|
||||
self.pg=Postgres('isard-apps-postgresql','moodle',app.config['MOODLE_POSTGRES_USER'],app.config['MOODLE_POSTGRES_PASSWORD'])
|
||||
self.pg=Postgres('isard-apps-postgresql','moodle',os.environ['MOODLE_POSTGRES_USER'],os.environ['MOODLE_POSTGRES_PASSWORD'])
|
||||
ready=True
|
||||
except:
|
||||
log.warning('Could not connect to moodle database. Retrying...')
|
||||
|
@ -35,8 +35,8 @@ class MoodleSaml():
|
|||
try:
|
||||
privatekey_pass=self.get_privatekey_pass()
|
||||
log.warning("The key: "+str(privatekey_pass))
|
||||
if privatekey_pass.endswith(app.config['DOMAIN']):
|
||||
app.config.setdefault('MOODLE_SAML_PRIVATEKEYPASS', privatekey_pass)
|
||||
if privatekey_pass.endswith(os.environ['DOMAIN']):
|
||||
app['config']['MOODLE_SAML_PRIVATEKEYPASS']=privatekey_pass
|
||||
ready=True
|
||||
except:
|
||||
# print(traceback.format_exc())
|
||||
|
@ -47,8 +47,8 @@ class MoodleSaml():
|
|||
ready=False
|
||||
while not ready:
|
||||
try:
|
||||
with open(os.path.join(app.root_path, "../moodledata/saml2/moodle."+app.config['DOMAIN']+".crt"),"r") as crt:
|
||||
app.config.setdefault('SP_CRT', crt.read())
|
||||
with open(os.path.join("./moodledata/saml2/moodle."+os.environ['DOMAIN']+".crt"),"r") as crt:
|
||||
app['config']['SP_CRT']=crt.read()
|
||||
ready=True
|
||||
except IOError:
|
||||
log.warning('Could not get moodle SAML2 crt certificate. Retrying...')
|
||||
|
@ -60,8 +60,8 @@ class MoodleSaml():
|
|||
ready=False
|
||||
while not ready:
|
||||
try:
|
||||
with open(os.path.join(app.root_path, "../moodledata/saml2/moodle."+app.config['DOMAIN']+".pem"),"r") as pem:
|
||||
app.config.setdefault('SP_PEM', pem.read())
|
||||
with open(os.path.join("./moodledata/saml2/moodle."+os.environ['DOMAIN']+".pem"),"r") as pem:
|
||||
app['config']['SP_PEM']=pem.read()
|
||||
ready=True
|
||||
except IOError:
|
||||
log.warning('Could not get moodle SAML2 pem certificate. Retrying...')
|
||||
|
@ -75,9 +75,9 @@ class MoodleSaml():
|
|||
## 1.- Bring up moodle and regenerate certificates on saml2 plugin in plugins-authentication
|
||||
## 2.- Execute this script
|
||||
## 3.- Cleanup all caches in moodle (Development tab)
|
||||
# with open(os.path.join(app.root_path, "../moodledata/saml2/"+app.config['MOODLE_SAML_PRIVATEKEYPASS'].replace("moodle."+app.config['DOMAIN'],'')+'.idp.xml'),"w") as xml:
|
||||
# with open(os.path.join("./moodledata/saml2/"+os.environ['MOODLE_SAML_PRIVATEKEYPASS'].replace("moodle."+os.environ['DOMAIN'],'')+'.idp.xml'),"w") as xml:
|
||||
# xml.write(self.parse_idp_metadata())
|
||||
with open(os.path.join(app.root_path, "../moodledata/saml2/0f635d0e0f3874fff8b581c132e6c7a7.idp.xml"),"w") as xml:
|
||||
with open(os.path.join("./moodledata/saml2/0f635d0e0f3874fff8b581c132e6c7a7.idp.xml"),"w") as xml:
|
||||
xml.write(self.parse_idp_metadata())
|
||||
|
||||
log.info('Written SP file on moodledata.')
|
||||
|
@ -86,8 +86,6 @@ class MoodleSaml():
|
|||
self.set_moodle_saml_plugin()
|
||||
self.set_keycloak_moodle_saml_plugin()
|
||||
|
||||
|
||||
|
||||
def activate_saml_plugin(self):
|
||||
## After you need to purge moodle caches: /var/www/html # php admin/cli/purge_caches.php
|
||||
return self.pg.update("""UPDATE "mdl_config" SET value = 'email,saml2' WHERE "name" = 'auth'""")
|
||||
|
@ -99,7 +97,7 @@ class MoodleSaml():
|
|||
keycloak=Keycloak()
|
||||
rsa=keycloak.get_server_rsa_key()
|
||||
keycloak=None
|
||||
return '<md:EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Name="urn:keycloak"><md:EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://sso.'+app.config['DOMAIN']+'/auth/realms/master"><md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo><ds:KeyName>'+rsa['name']+'</ds:KeyName><ds:X509Data><ds:X509Certificate>'+rsa['certificate']+'</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml/resolve" index="0"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.'+app.config['DOMAIN']+'/auth/realms/master/protocol/saml"/></md:IDPSSODescriptor></md:EntityDescriptor></md:EntitiesDescriptor>'
|
||||
return '<md:EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Name="urn:keycloak"><md:EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master"><md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo><ds:KeyName>'+rsa['name']+'</ds:KeyName><ds:X509Data><ds:X509Certificate>'+rsa['certificate']+'</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml/resolve" index="0"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://sso.'+os.environ['DOMAIN']+'/auth/realms/master/protocol/saml"/></md:IDPSSODescriptor></md:EntityDescriptor></md:EntitiesDescriptor>'
|
||||
|
||||
def set_keycloak_moodle_saml_plugin(self):
|
||||
keycloak=Keycloak()
|
||||
|
@ -121,4 +119,7 @@ class MoodleSaml():
|
|||
for name in config.keys():
|
||||
self.pg.update("""UPDATE "mdl_config_plugins" SET value = '%s' WHERE "plugin" = 'auth_saml2' AND "name" = '%s'""" % (config[name],name))
|
||||
self.pg.update("""INSERT INTO "mdl_auth_saml2_idps" ("metadataurl", "entityid", "activeidp", "defaultidp", "adminidp", "defaultname", "displayname", "logo", "alias", "whitelist") VALUES
|
||||
('xml', 'https://sso.%s/auth/realms/master', 1, 0, 0, 'Login via SAML2', '', NULL, NULL, NULL);""" % (app.config['DOMAIN']))
|
||||
('xml', 'https://sso.%s/auth/realms/master', 1, 0, 0, 'Login via SAML2', '', NULL, NULL, NULL);""" % (os.environ['DOMAIN']))
|
||||
|
||||
|
||||
m=MoodleSaml()
|
Loading…
Reference in New Issue