digitaldemocratic/dd-sso/admin/src/wordpress_saml_onlycerts.py

179 lines
6.7 KiB
Python

#
# Copyright © 2021,2022 IsardVDI S.L.
#
# This file is part of DD
#
# DD is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# DD is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License
# along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import json
import logging as log
import os
import pprint
import random
import string
import time
import traceback
from datetime import datetime, timedelta
import psycopg2
import yaml
from admin.lib.keycloak_client import KeycloakClient
from admin.lib.mysql import Mysql
app = {}
app["config"] = {}
class WordpressSaml:
def __init__(self):
self.url = "http://dd-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(
"dd-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_certs()
except:
print(traceback.format_exc())
print("Error resetting saml certs on wordpress")
try:
self.set_wordpress_saml_plugin_certs()
except:
print(traceback.format_exc())
print("Error adding saml on wordpress")
# SAML clients don't work well with composite roles so disabling and adding on realm
# 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.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 connect(self):
self.keycloak = KeycloakClient(
url=self.url,
username=self.username,
password=self.password,
realm=self.realm,
verify=self.verify,
)
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_wordpress_saml_plugin_certs(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_idp_x509cert', '%s', 'yes'),
('onelogin_saml_advanced_settings_sp_x509cert', '%s', 'yes'),
('onelogin_saml_advanced_settings_sp_privatekey', '%s', 'yes');"""
% (
self.parse_idp_cert(),
app["config"]["PUBLIC_CERT"],
app["config"]["PRIVATE_KEY"],
)
)
def reset_saml_certs(self):
self.db.update(
"""DELETE FROM wp_options WHERE option_name = 'onelogin_saml_idp_x509cert'"""
)
self.db.update(
"""DELETE FROM wp_options WHERE option_name = 'onelogin_saml_advanced_settings_sp_x509cert'"""
)
self.db.update(
"""DELETE FROM wp_options WHERE option_name = 'onelogin_saml_advanced_settings_sp_privatekey'"""
)
nw = WordpressSaml()