# # 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 . # # 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.postgres import Postgres app = {} app["config"] = {} class NextcloudSaml: 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.pg = Postgres( "dd-apps-postgresql", "nextcloud", os.environ["NEXTCLOUD_POSTGRES_USER"], os.environ["NEXTCLOUD_POSTGRES_PASSWORD"], ) ready = True except: log.warning("Could not connect to nextcloud database. Retrying...") time.sleep(2) log.info("Connected to nextcloud database.") ready = False while not ready: try: with open(os.path.join("./saml_certs/public.cert"), "r") as crt: app["config"]["PUBLIC_CERT"] = crt.read() ready = True except IOError: log.warning( "Could not get public certificate to be used in nextcloud. 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 nextcloud.") ready = False while not ready: try: with open(os.path.join("./saml_certs/private.key"), "r") as pem: app["config"]["PRIVATE_KEY"] = pem.read() ready = True except IOError: log.warning( "Could not get private key to be used in nextcloud. 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 nextcloud.") # ## 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("Error resetting saml on nextcloud") try: self.set_nextcloud_saml_plugin_certs() except: log.error(traceback.format_exc()) print("Error adding saml on nextcloud") 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'""") # def get_privatekey_pass(self): # return self.pg.select("""SELECT * FROM "mdl_config" WHERE "name" = 'siteidentifier'""")[0][2] def parse_idp_cert(self): self.connect() rsa = self.keycloak.get_server_rsa_key() self.keycloak = None return rsa["certificate"] def set_nextcloud_saml_plugin_certs(self): self.pg.update( """INSERT INTO "oc_appconfig" ("appid", "configkey", "configvalue") VALUES ('user_saml', 'sp-privateKey', '%s'), ('user_saml', 'idp-x509cert', '%s'), ('user_saml', 'sp-x509cert', '%s');""" % ( app["config"]["PRIVATE_KEY"], self.parse_idp_cert(), app["config"]["PUBLIC_CERT"], ) ) def reset_saml_certs(self): cfg_list = ["sp-privateKey", "idp-x509cert", "sp-x509cert"] for cfg in cfg_list: self.pg.update( """DELETE FROM "oc_appconfig" WHERE appid = 'user_saml' AND configkey = '%s'""" % (cfg) ) n = NextcloudSaml()