Skip to content
Snippets Groups Projects
Commit be28c1ae authored by Josep Maria Viñolas Auquer's avatar Josep Maria Viñolas Auquer
Browse files

automated wordpress saml

parent ab559dd3
Branches
No related tags found
No related merge requests found
......@@ -16,3 +16,4 @@ zope.event==4.4
zope.interface==5.1.0
psycopg2==2.8.6
Flask-SocketIO==2.8.6
mysql-connector-python==8.0.25
\ No newline at end of file
from admin import app
from .keycloak import Keycloak
from .keycloak_client import KeycloakClient
from .moodle import Moodle
from .nextcloud import Nextcloud
import logging as log
from pprint import pprint
import traceback
import traceback, os
from time import sleep
from .nextcloud_exc import *
from .helpers import filter_roles_list, filter_roles_listofdicts
......@@ -13,12 +15,42 @@ from .helpers import filter_roles_list, filter_roles_listofdicts
from flask_socketio import SocketIO, emit, join_room, leave_room, \
close_room, rooms, disconnect, send
socketio = SocketIO(app)
import json
class Admin():
def __init__(self):
self.keycloak=Keycloak(verify=app.config['VERIFY'])
ready=False
while not ready:
try:
self.keycloak=KeycloakClient(verify=app.config['VERIFY'])
ready=True
except:
log.error(traceback.format_exc())
log.error('Could not connect to keycloak, waiting to be online...')
sleep(2)
log.warning('Keycloak connected.')
ready=False
while not ready:
try:
self.moodle=Moodle(verify=app.config['VERIFY'])
ready=True
except:
log.error('Could not connect to moodle, waiting to be online...')
sleep(2)
log.warning('Moodle connected.')
ready=False
while not ready:
try:
self.nextcloud=Nextcloud(verify=app.config['VERIFY'])
ready=True
except:
log.error('Could not connect to nextcloud, waiting to be online...')
sleep(2)
log.warning('Nextcloud connected.')
self.default_setup()
self.internal={}
self.resync_data()
......@@ -26,6 +58,52 @@ class Admin():
'groups':[],
'roles':[]}
## This function should be moved to postup.py
def default_setup(self):
log.warning('Setting defaults...')
dduser=os.environ['DDADMIN_USER']
ddpassword=os.environ['DDADMIN_PASSWORD']
ddmail=os.environ['DDADMIN_EMAIL']
try:
log.warning('KEYCLOAK: Adding group admin and user admin to this group')
self.keycloak.add_group('admin')
## Add default admin user to group admin (for nextcloud, just in case we go there)
admin_uid=self.keycloak_admin.get_user_id('admin')
self.keycloak_admin.group_user_add(uid,gid)
log.warning('KEYCLOAK: OK')
except:
log.warning('KEYCLOAK: Seems to be there already')
try:
log.warning('KEYCLOAK: Adding user ddadmin and adding to group and role admin')
## Assign group admin to this dduser for nextcloud
uid=self.keycloak.add_user(dduser,'DD','Admin',ddmail,ddpassword,group='admin')
## Assign role admin to this user for keycloak, moodle and wordpress
self.keycloak.assign_realm_roles(uid,'admin')
log.warning('KEYCLOAK: OK')
except:
log.warning('KEYCLOAK: Seems to be there already')
try:
log.warning('NEXTCLOUD: Adding user ddadmin and adding to group admin')
self.nextcloud.add_user(dduser,ddpassword,group='admin',email=ddmail,displayname='DD Admin')
log.warning('NEXTCLOUD: OK')
except ProviderItemExists:
log.warning('NEXTCLOUD: Seems to be there already')
except:
log.error(traceback.format_exc())
exit(1)
try:
log.warning('MOODLE: Adding user ddadmin and adding to siteadmins')
self.moodle.create_user(ddmail,dduser,ddpassword,'DD','Admin')
uid=self.moodle.get_user_by('username',dduser)['users'][0]['id']
self.moodle.add_user_to_siteadmin(uid)
log.warning('MOODLE: OK')
except:
log.warning('MOODLE: Seems to be there already')
def resync_data(self):
self.internal={'users':self._get_mix_users(),
'groups':self._get_mix_groups(),
......@@ -146,15 +224,15 @@ class Admin():
return filter_roles_listofdicts(self.keycloak.get_roles())
def get_keycloak_groups(self):
log.warning('Loading keycloak groups... can take a long time...')
log.warning('Loading keycloak groups...')
return self.keycloak.get_groups()
def get_moodle_groups(self):
log.warning('Loading moodle groups... can take a long time...')
log.warning('Loading moodle groups...')
return self.moodle.get_cohorts()
def get_nextcloud_groups(self):
log.warning('Loading nextcloud groups... can take a long time...')
log.warning('Loading nextcloud groups...')
return self.nextcloud.get_groups_list()
def get_mix_groups(self):
......@@ -244,24 +322,24 @@ class Admin():
def sync_external(self):
for u in self.external['users']:
log.error('Creating user: '+u['username'])
log.info('Creating user: '+u['username'])
self.keycloak.add_user(u['username'],u['first'],u['last'],u['email'],'1Provaprovaprova',group=u['groups'][0])
def sync_to_moodle(self):
for u in self.internal['users']:
if not u['moodle']:
log.error('Creating moodle user: '+u['username'])
log.info('Creating moodle user: '+u['username'])
self.moodle.create_user(u['email'],u['username'],'-1Provaprovaprova',u['first'],u['last'])
def sync_to_nextcloud(self):
for u in self.internal['users']:
if not u['nextcloud']:
log.error('Creating nextcloud user: '+u['username'])
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'])
except ProviderItemExists:
log.error('User '+u['username']+' already exists. Skipping...')
log.info('User '+u['username']+' already exists. Skipping...')
continue
except:
log.error(traceback.format_exc())
......
......@@ -14,7 +14,7 @@ from jinja2 import Environment, FileSystemLoader
from keycloak import KeycloakAdmin
from .postgres import Postgres
class Keycloak():
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
......@@ -31,7 +31,7 @@ class Keycloak():
self.realm=realm
self.verify=verify
self.keycloak_pg=Postgres('isard-apps-postgresql','keycloak',app.config['KEYCLOAK_POSTGRES_USER'],app.config['KEYCLOAK_POSTGRES_PASSWORD'])
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,
......@@ -39,7 +39,7 @@ class Keycloak():
password=self.password,
realm_name=self.realm,
verify=self.verify)
# from keycloak import KeycloakAdmin
# 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
......@@ -110,7 +110,6 @@ class Keycloak():
def add_user(self,username,first,last,email,password,group=False):
# Returns user id
log.error('Creating group: '+str(group))
self.connect()
username=username.lower()
try:
......@@ -123,22 +122,21 @@ class Keycloak():
"value":password,
"temporary":False}]})
except:
uid=self.keycloak_admin.get_user_id(username)
log.error(uid)
log.error(traceback.format_exc())
if group:
path = '/'+group if group[1:] != '/' else 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))
gid=self.keycloak_admin.get_group_by_path(path=path,search_in_subgroups=False)['id']
except:
self.keycloak_admin.create_group({"name":group})
gid=self.keycloak_admin.get_group_by_path(group)['id']
log.error(gid)
gid=self.keycloak_admin.get_group_by_path(path)['id']
self.keycloak_admin.group_user_add(uid,gid)
return uid
def add_user_role(self,client_id,user_id,role_id,role_name):
self.connect()
return self.keycloak_admin.assign_client_role(client_id="client_id", user_id="user_id", role_id="role_id", role_name="test")
return self.keycloak_admin.assign_client_role(client_id=client_id, user_id=user_id, role_id=role_id, role_name="test")
def delete_user(self,userid):
self.connect()
......@@ -196,8 +194,9 @@ class Keycloak():
self.connect()
return self.keycloak_admin.get_client_roles(client_id=client_id)
# def add_client_role(self,client_id,roleName):
# return self.keycloak_admin.create_client_role(client_id=client_id, {'name': roleName, 'clientRole': True})
def add_client_role(self,client_id,name,description=''):
self.connect()
return self.keycloak_admin.create_client_role(client_id, {'name': name, 'description':description, 'clientRole': True})
## SYSTEM
......@@ -214,6 +213,15 @@ class Keycloak():
rsa_key = [k for k in self.keycloak_admin.get_keys()['keys'] if k['type']=='RSA'][0]
return {'name':rsa_key['kid'],'certificate':rsa_key['certificate']}
## REALM
def assign_realm_roles(self, user_id, role):
self.connect()
try:
role=[r for r in self.keycloak_admin.get_realm_roles() if r['name']==role]
except:
return False
return self.keycloak_admin.assign_realm_roles(user_id=user_id, client_id=None, roles=role)
## CLIENTS
def delete_client(self,clientid):
self.connect()
......
......@@ -122,3 +122,36 @@ class Moodle():
for cohort in cohorts:
if user_id in self.get_cohort_members(cohort['id']): user_cohorts.append(cohort)
return user_cohorts
def add_user_to_siteadmin(self,user_id):
q = """SELECT value FROM mdl_config WHERE name='siteadmins'"""
value=self.moodle_pg.select(q)[0][0]
if str(user_id) not in value:
value=value+','+str(user_id)
q = """UPDATE mdl_config SET value = '%s' WHERE name='siteadmins'""" % (value)
self.moodle_pg.update(q)
log.warning('MOODLE:ADDING THE USER TO ADMINS: This needs a purge cache in moodle!')
# def add_role_to_user(self, user_id, role='admin', context='missing'):
# if role=='admin':
# role_id=1
# else:
# return False
# assignments = [{'roleid': role_id, 'userid': user_id, 'contextid': 0}]
# self.call('core_role_assign_roles', assignments=assignments)
# userid=user_id, role_id=role_id)
# 'contextlevel': 1,
# define('CONTEXT_SYSTEM', 10);
# define('CONTEXT_USER', 30);
# define('CONTEXT_COURSECAT', 40);
# define('CONTEXT_COURSE', 50);
# define('CONTEXT_MODULE', 70);
# define('CONTEXT_BLOCK', 80);
# 'contextlevel': , 'instanceid'
# $assignment = array( 'roleid' => $role_id, 'userid' => $user_id, 'contextid' => $context_id );
# $assignments = array( $assignment );
# $params = array( 'assignments' => $assignments );
# $response = call_moodle( 'core_role_assign_roles', $params, $token );
\ No newline at end of file
#!/usr/bin/env python
# coding=utf-8
import time
from admin import app
from datetime import datetime, timedelta
import pprint
import logging as log
import traceback
import yaml, json
import mysql.connector
class Mysql():
def __init__(self,host,database,user,password):
self.conn = mysql.connector.connect(
host=host,
database=database,
user=user,
password=password)
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()
......@@ -126,11 +126,14 @@ class Nextcloud():
# log.error(traceback.format_exc())
# raise
def add_user(self,userid,userpassword,quota,group=False,email='',displayname=''):
if group:
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}
else:
data={'userid':userid,'password':userpassword,'quota':quota,'email':email,'displayname':displayname}
if not group: del data['group']
if not quota: del data['quota']
# 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',
......
......@@ -82,6 +82,7 @@ class Postup():
(3, 'core_cohort_delete_cohorts'),
(3, 'core_cohort_search_cohorts'),
(3, 'core_cohort_update_cohorts'),
(3, 'core_role_assign_roles'),
(3, 'core_cohort_get_cohorts');""")
self.pg.update("""INSERT INTO "mdl_external_services_users" ("externalserviceid", "userid", "iprestriction", "validuntil", "timecreated") VALUES
......
......@@ -11,7 +11,7 @@ import yaml, json
import psycopg2
from admin.lib.postgres import Postgres
from admin.lib.keycloak import Keycloak
from admin.lib.keycloak_client import KeycloakClient
import string, random
......@@ -102,6 +102,8 @@ class MoodleSaml():
except:
print('Error adding saml on keycloak')
self.add_client_roles()
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'""")
......@@ -110,18 +112,18 @@ class MoodleSaml():
return self.pg.select("""SELECT * FROM "mdl_config" WHERE "name" = 'siteidentifier'""")[0][2]
def parse_idp_metadata(self):
keycloak=Keycloak()
keycloak=KeycloakClient()
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.'+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()
keycloak=KeycloakClient()
keycloak.add_moodle_client()
keycloak=None
def delete_keycloak_moodle_saml_plugin(self):
keycloak=Keycloak()
keycloak=KeycloakClient()
keycloak.delete_client('a92d5417-92b6-4678-9cb9-51bc0edcee8c')
keycloak=None
......@@ -240,9 +242,16 @@ class MoodleSaml():
"manage" : True
}
}
keycloak=Keycloak()
keycloak=KeycloakClient()
keycloak.add_client(client)
keycloak=None
def add_client_roles(self):
keycloak=KeycloakClient()
keycloak.add_client_role('a92d5417-92b6-4678-9cb9-51bc0edcee8c','admin','Moodle admins')
keycloak.add_client_role('a92d5417-92b6-4678-9cb9-51bc0edcee8c','manager','Moodle managers')
keycloak.add_client_role('a92d5417-92b6-4678-9cb9-51bc0edcee8c','teacher','Moodle teachers')
keycloak.add_client_role('a92d5417-92b6-4678-9cb9-51bc0edcee8c','student','Moodle students')
keycloak=None
m=MoodleSaml()
......@@ -11,7 +11,7 @@ import yaml, json
import psycopg2
from admin.lib.postgres import Postgres
from admin.lib.keycloak import Keycloak
from admin.lib.keycloak_client import KeycloakClient
import string, random
......@@ -20,6 +20,12 @@ app['config']={}
class NextcloudSaml():
def __init__(self):
self.url="http://isard-sso-keycloak:8080/auth/"
self.username=os.environ['KEYCLOAK_USER']
self.password=os.environ['KEYCLOAK_PASSWORD']
self.realm='master'
self.verify=True
ready=False
while not ready:
try:
......@@ -81,6 +87,7 @@ class NextcloudSaml():
try:
self.set_nextcloud_saml_plugin()
except:
log.error(traceback.format_exc())
print('Error adding saml on nextcloud')
try:
......@@ -88,6 +95,13 @@ class NextcloudSaml():
except:
print('Error adding saml on keycloak')
def connect(self):
self.keycloak= KeycloakClient(url=self.url,
username=self.username,
password=self.password,
realm=self.realm,
verify=self.verify)
# 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'""")
......@@ -96,20 +110,20 @@ class NextcloudSaml():
# return self.pg.select("""SELECT * FROM "mdl_config" WHERE "name" = 'siteidentifier'""")[0][2]
def parse_idp_cert(self):
keycloak=Keycloak()
rsa=keycloak.get_server_rsa_key()
keycloak=None
self.connect()
rsa=self.keycloak.get_server_rsa_key()
self.keycloak=None
return rsa['certificate']
def set_keycloak_nextcloud_saml_plugin(self):
keycloak=Keycloak()
keycloak.add_nextcloud_client()
keycloak=None
self.connect()
self.keycloak.add_nextcloud_client()
self.keycloak=None
def delete_keycloak_nextcloud_saml_plugin(self):
keycloak=Keycloak()
keycloak.delete_client('bef873f0-2079-4876-8657-067de27d01b7')
keycloak=None
self.connect()
self.keycloak.delete_client('bef873f0-2079-4876-8657-067de27d01b7')
self.keycloak=None
def set_nextcloud_saml_plugin(self):
self.pg.update("""INSERT INTO "oc_appconfig" ("appid", "configkey", "configvalue") VALUES
......@@ -235,10 +249,8 @@ class NextcloudSaml():
"manage" : True
}
}
keycloak=Keycloak()
keycloak.add_client(client)
keycloak=None
self.connect()
self.keycloak.add_client(client)
self.keycloak=None
n=NextcloudSaml()
\ No newline at end of file
#!/usr/bin/env python
# coding=utf-8
import time, os
from datetime import datetime, timedelta
import pprint
import logging as log
import traceback
import yaml, json
import psycopg2
from admin.lib.mysql import Mysql
from admin.lib.keycloak_client import KeycloakClient
import string, random
app={}
app['config']={}
class WordpressSaml():
def __init__(self):
self.url="http://isard-sso-keycloak:8080/auth/"
self.username=os.environ['KEYCLOAK_USER']
self.password=os.environ['KEYCLOAK_PASSWORD']
self.realm='master'
self.verify=True
ready=False
while not ready:
try:
self.db=Mysql('isard-apps-mariadb','wordpress','root',os.environ['MARIADB_PASSWORD'])
ready=True
except:
log.warning('Could not connect to wordpress database. Retrying...')
time.sleep(2)
log.info('Connected to wordpress database.')
ready=False
while not ready:
try:
with open(os.path.join("./saml_certs/public.cert"),"r") as crt:
app['config']['PUBLIC_CERT_RAW']=crt.read()
app['config']['PUBLIC_CERT']=self.cert_prepare(app['config']['PUBLIC_CERT_RAW'])
ready=True
except IOError:
log.warning('Could not get public certificate to be used in wordpress. Retrying...')
log.warning(' You should generate them: /admin/saml_certs # openssl req -nodes -new -x509 -keyout private.key -out public.cert')
time.sleep(2)
except:
log.error(traceback.format_exc())
log.info('Got moodle srt certificate to be used in wordpress.')
ready=False
while not ready:
try:
with open(os.path.join("./saml_certs/private.key"),"r") as pem:
app['config']['PRIVATE_KEY']=self.cert_prepare(pem.read())
ready=True
except IOError:
log.warning('Could not get private key to be used in wordpress. Retrying...')
log.warning(' You should generate them: /admin/saml_certs # openssl req -nodes -new -x509 -keyout private.key -out public.cert')
time.sleep(2)
log.info('Got moodle pem certificate to be used in wordpress.')
# ## This seems related to the fact that the certificate generated the first time does'nt work.
# ## And when regenerating the certificate de privatekeypass seems not to be used and instead it
# ## will use always this code as filename: 0f635d0e0f3874fff8b581c132e6c7a7
# ## As this bug I'm not able to solve, the process is:
# ## 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("./moodledata/saml2/"+os.environ['NEXTCLOUD_SAML_PRIVATEKEYPASS'].replace("moodle."+os.environ['DOMAIN'],'')+'.idp.xml'),"w") as xml:
# # xml.write(self.parse_idp_metadata())
# with open(os.path.join("./moodledata/saml2/0f635d0e0f3874fff8b581c132e6c7a7.idp.xml"),"w") as xml:
# xml.write(self.parse_idp_metadata())
try:
self.reset_saml()
except:
print(traceback.format_exc())
print('Error resetting saml on wordpress')
try:
self.delete_keycloak_wordpress_saml_plugin()
except:
print('Error resetting saml on keycloak')
try:
self.set_wordpress_saml_plugin()
except:
print(traceback.format_exc())
print('Error adding saml on wordpress')
try:
self.add_keycloak_wordpress_saml()
except:
print('Error adding saml on keycloak')
self.add_client_roles()
def connect(self):
self.keycloak= KeycloakClient(url=self.url,
username=self.username,
password=self.password,
realm=self.realm,
verify=self.verify)
# def activate_saml_plugin(self):
# ## After you need to purge moodle caches: /var/www/html # php admin/cli/purge_caches.php
# return self.db.update("""UPDATE "mdl_config" SET value = 'email,saml2' WHERE "name" = 'auth'""")
# def get_privatekey_pass(self):
# return self.db.select("""SELECT * FROM "mdl_config" WHERE "name" = 'siteidentifier'""")[0][2]
def cert_prepare(self,cert):
return ''.join(cert.split('-----')[2].splitlines())
def parse_idp_cert(self):
self.connect()
rsa=self.keycloak.get_server_rsa_key()
self.keycloak=None
return rsa['certificate']
def set_keycloak_wordpress_saml_plugin(self):
self.connect()
self.keycloak.add_wordpress_client()
self.keycloak=None
def delete_keycloak_wordpress_saml_plugin(self):
self.connect()
self.keycloak.delete_client('630601f8-25d1-4822-8741-c93affd2cd84')
self.keycloak=None
def set_wordpress_saml_plugin(self):
# ('active_plugins', 'a:2:{i:0;s:33:\"edwiser-bridge/edwiser-bridge.php\";i:1;s:17:\"onelogin_saml.php\";}', 'yes'),
self.db.update("""INSERT INTO wp_options (option_name, option_value, autoload) VALUES
('onelogin_saml_enabled', 'on', 'yes'),
('onelogin_saml_idp_entityid', 'Saml Login', 'yes'),
('onelogin_saml_idp_sso', 'https://sso.%s/auth/realms/master/protocol/saml', 'yes'),
('onelogin_saml_idp_slo', 'https://sso.%s/auth/realms/master/protocol/saml', 'yes'),
('onelogin_saml_idp_x509cert', '%s', 'yes'),
('onelogin_saml_autocreate', 'on', 'yes'),
('onelogin_saml_updateuser', 'on', 'yes'),
('onelogin_saml_forcelogin', 'on', 'yes'),
('onelogin_saml_slo', 'on', 'yes'),
('onelogin_saml_keep_local_login', '', 'yes'),
('onelogin_saml_alternative_acs', '', 'yes'),
('onelogin_saml_account_matcher', 'username', 'yes'),
('onelogin_saml_trigger_login_hook', '', 'yes'),
('onelogin_saml_multirole', '', 'yes'),
('onelogin_saml_trusted_url_domains', '', 'yes'),
('onelogin_saml_attr_mapping_username', 'username', 'yes'),
('onelogin_saml_attr_mapping_mail', 'email', 'yes'),
('onelogin_saml_attr_mapping_firstname', 'givenName', 'yes'),
('onelogin_saml_attr_mapping_lastname', 'sn', 'yes'),
('onelogin_saml_attr_mapping_nickname', '', 'yes'),
('onelogin_saml_attr_mapping_role', 'Role', 'yes'),
('onelogin_saml_attr_mapping_rememberme', '', 'yes'),
('onelogin_saml_role_mapping_administrator', 'admin', 'yes'),
('onelogin_saml_role_mapping_editor', 'manager', 'yes'),
('onelogin_saml_role_mapping_author', 'coursecreator', 'yes'),
('onelogin_saml_role_mapping_contributor', 'teacher', 'yes'),
('onelogin_saml_role_mapping_subscriber', '', 'yes'),
('onelogin_saml_role_mapping_multivalued_in_one_attribute_value', 'on', 'yes'),
('onelogin_saml_role_mapping_multivalued_pattern', '', 'yes'),
('onelogin_saml_role_order_administrator', '', 'yes'),
('onelogin_saml_role_order_editor', '', 'yes'),
('onelogin_saml_role_order_author', '', 'yes'),
('onelogin_saml_role_order_contributor', '', 'yes'),
('onelogin_saml_role_order_subscriber', '', 'yes'),
('onelogin_saml_customize_action_prevent_local_login', '', 'yes'),
('onelogin_saml_customize_action_prevent_reset_password', '', 'yes'),
('onelogin_saml_customize_action_prevent_change_password', '', 'yes'),
('onelogin_saml_customize_action_prevent_change_mail', '', 'yes'),
('onelogin_saml_customize_stay_in_wordpress_after_slo', 'on', 'yes'),
('onelogin_saml_customize_links_user_registration', '', 'yes'),
('onelogin_saml_customize_links_lost_password', '', 'yes'),
('onelogin_saml_customize_links_saml_login', '', 'yes'),
('onelogin_saml_advanced_settings_debug', '', 'yes'),
('onelogin_saml_advanced_settings_strict_mode', '', 'yes'),
('onelogin_saml_advanced_settings_sp_entity_id', '', 'yes'),
('onelogin_saml_advanced_idp_lowercase_url_encoding', '', 'yes'),
('onelogin_saml_advanced_settings_nameid_encrypted', '', 'yes'),
('onelogin_saml_advanced_settings_authn_request_signed', 'on', 'yes'),
('onelogin_saml_advanced_settings_logout_request_signed', 'on', 'yes'),
('onelogin_saml_advanced_settings_logout_response_signed', 'on', 'yes'),
('onelogin_saml_advanced_settings_want_message_signed', '', 'yes'),
('onelogin_saml_advanced_settings_want_assertion_signed', '', 'yes'),
('onelogin_saml_advanced_settings_want_assertion_encrypted', '', 'yes'),
('onelogin_saml_advanced_settings_retrieve_parameters_from_server', '', 'yes'),
('onelogin_saml_advanced_nameidformat', 'unspecified', 'yes'),
('onelogin_saml_advanced_requestedauthncontext', '', 'yes'),
('onelogin_saml_advanced_settings_sp_x509cert', '%s', 'yes'),
('onelogin_saml_advanced_settings_sp_privatekey', '%s', 'yes'),
('onelogin_saml_advanced_signaturealgorithm', 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 'yes'),
('onelogin_saml_advanced_digestalgorithm', 'http://www.w3.org/2000/09/xmldsig#sha1', 'yes');""" % (os.environ['DOMAIN'],os.environ['DOMAIN'],self.parse_idp_cert(),app['config']['PUBLIC_CERT'],app['config']['PRIVATE_KEY']))
def reset_saml(self):
self.db.update("""DELETE FROM wp_options WHERE option_name LIKE 'onelogin_saml_%'""")
def add_keycloak_wordpress_saml(self):
client={"id" : "630601f8-25d1-4822-8741-c93affd2cd84",
"clientId" : "php-saml",
"surrogateAuthRequired" : False,
"enabled" : True,
"alwaysDisplayInConsole" : False,
"clientAuthenticatorType" : "client-secret",
"redirectUris" : [ "https://wp."+os.environ['DOMAIN']+"/wp-login.php?saml_acs" ],
"webOrigins" : [ "https://wp."+os.environ['DOMAIN'] ],
"notBefore" : 0,
"bearerOnly" : False,
"consentRequired" : False,
"standardFlowEnabled" : True,
"implicitFlowEnabled" : False,
"directAccessGrantsEnabled" : False,
"serviceAccountsEnabled" : False,
"publicClient" : False,
"frontchannelLogout" : True,
"protocol" : "saml",
"attributes" : {
"saml.force.post.binding" : True,
"saml_assertion_consumer_url_post" : "https://wp."+os.environ['DOMAIN']+"/wp-login.php?saml_acs",
"saml.server.signature" : True,
"saml.server.signature.keyinfo.ext" : False,
"saml.signing.certificate" : app['config']['PUBLIC_CERT_RAW'],
"saml_single_logout_service_url_redirect" : "https://wp."+os.environ['DOMAIN']+"/wp-login.php?saml_sls",
"saml.signature.algorithm" : "RSA_SHA256",
"saml_force_name_id_format" : False,
"saml.client.signature" : True,
"saml.authnstatement" : True,
"saml_name_id_format" : "username",
"saml_signature_canonicalization_method" : "http://www.w3.org/2001/10/xml-exc-c14n#"
},
"authenticationFlowBindingOverrides" : { },
"fullScopeAllowed" : True,
"nodeReRegistrationTimeout" : -1,
"protocolMappers" : [ {
"id" : "72c6175e-bd07-4c27-abd6-4e4ae38d834b",
"name" : "username",
"protocol" : "saml",
"protocolMapper" : "saml-user-attribute-mapper",
"consentRequired" : False,
"config" : {
"attribute.nameformat" : "Basic",
"user.attribute" : "username",
"friendly.name" : "username",
"attribute.name" : "username"
}
}, {
"id" : "abd6562f-4732-4da9-987f-b1a6ad6605fa",
"name" : "roles",
"protocol" : "saml",
"protocolMapper" : "saml-role-list-mapper",
"consentRequired" : False,
"config" : {
"single" : True,
"attribute.nameformat" : "Basic",
"friendly.name" : "Roles",
"attribute.name" : "Role"
}
}, {
"id" : "50aafb71-d91c-4bc7-bb60-e1ae0222aab3",
"name" : "email",
"protocol" : "saml",
"protocolMapper" : "saml-user-property-mapper",
"consentRequired" : False,
"config" : {
"attribute.nameformat" : "Basic",
"user.attribute" : "email",
"friendly.name" : "email",
"attribute.name" : "email"
}
} ],
"defaultClientScopes" : [ "web-origins", "role_list", "roles", "profile", "email" ],
"optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ],
"access" : {
"view" : True,
"configure" : True,
"manage" : True
}
}
self.connect()
self.keycloak.add_client(client)
self.keycloak=None
def add_client_roles(self):
self.connect()
self.keycloak.add_client_role('630601f8-25d1-4822-8741-c93affd2cd84','admin','Moodle admins')
self.keycloak.add_client_role('630601f8-25d1-4822-8741-c93affd2cd84','manager','Moodle managers')
self.keycloak.add_client_role('630601f8-25d1-4822-8741-c93affd2cd84','teacher','Moodle teachers')
self.keycloak.add_client_role('630601f8-25d1-4822-8741-c93affd2cd84','student','Moodle students')
self.keycloak=None
nw=WordpressSaml()
\ No newline at end of file
......@@ -28,6 +28,8 @@ services:
- KEYCLOAK_PASSWORD=${KEYCLOAK_PASSWORD}
- PROXY_ADDRESS_FORWARDING=true
- KEYCLOAK_FRONTEND_URL=https://sso.${DOMAIN}/auth/
- DDADMIN_USER=${DDADMIN_USER}
- DDADMIN_PASSWORD=${DDADMIN_PASSWORD}
#- KEYCLOAK_LOGLEVEL=ALL
#- Dkeycloak.profile.feature.upload_scripts=enabled
depends_on:
......
......@@ -15,3 +15,6 @@
# #curl https://moodle.isardvdi.site/auth/saml2/sp/metadata.php
# # Import as client provider
# get-roles --cclientid test-client --rolename operations
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment