258 lines
11 KiB
Python
258 lines
11 KiB
Python
#!/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.postgres import Postgres
|
|
from admin.lib.keycloak_client import KeycloakClient
|
|
|
|
import string, random
|
|
|
|
app={}
|
|
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:
|
|
self.pg=Postgres('isard-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()
|
|
except:
|
|
print('Error resetting saml on nextcloud')
|
|
|
|
try:
|
|
self.delete_keycloak_nextcloud_saml_plugin()
|
|
except:
|
|
print('Error resetting saml on keycloak')
|
|
|
|
try:
|
|
self.set_nextcloud_saml_plugin()
|
|
except:
|
|
log.error(traceback.format_exc())
|
|
print('Error adding saml on nextcloud')
|
|
|
|
try:
|
|
self.add_keycloak_nextcloud_saml()
|
|
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'""")
|
|
|
|
# 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_keycloak_nextcloud_saml_plugin(self):
|
|
self.connect()
|
|
self.keycloak.add_nextcloud_client()
|
|
self.keycloak=None
|
|
|
|
def delete_keycloak_nextcloud_saml_plugin(self):
|
|
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
|
|
('user_saml', 'general-uid_mapping', 'username'),
|
|
('user_saml', 'type', 'saml'),
|
|
('user_saml', 'sp-privateKey', '%s'),
|
|
('user_saml', 'saml-attribute-mapping-email_mapping', 'email'),
|
|
('user_saml', 'saml-attribute-mapping-quota_mapping', 'quota'),
|
|
('user_saml', 'saml-attribute-mapping-displayName_mapping', 'displayname'),
|
|
('user_saml', 'saml-attribute-mapping-group_mapping', 'member'),
|
|
('user_saml', 'idp-entityId', 'https://sso.%s/auth/realms/master'),
|
|
('user_saml', 'idp-singleSignOnService.url', 'https://sso.%s/auth/realms/master/protocol/saml'),
|
|
('user_saml', 'idp-x509cert', '%s'),
|
|
('user_saml', 'security-authnRequestsSigned', '1'),
|
|
('user_saml', 'security-logoutRequestSigned', '1'),
|
|
('user_saml', 'security-logoutResponseSigned', '1'),
|
|
('user_saml', 'security-wantMessagesSigned', '1'),
|
|
('user_saml', 'security-wantAssertionsSigned', '1'),
|
|
('user_saml', 'general-idp0_display_name', 'SAML Login'),
|
|
('user_saml', 'sp-x509cert', '%s'),
|
|
('user_saml', 'idp-singleLogoutService.url', 'https://sso.%s/auth/realms/master/protocol/saml');""" % (app['config']['PRIVATE_KEY'],os.environ['DOMAIN'],os.environ['DOMAIN'],self.parse_idp_cert(),app['config']['PUBLIC_CERT'],os.environ['DOMAIN']))
|
|
|
|
|
|
def reset_saml(self):
|
|
cfg_list=['general-uid_mapping',
|
|
'sp-privateKey',
|
|
'saml-attribute-mapping-email_mapping',
|
|
'saml-attribute-mapping-group_mapping',
|
|
'idp-entityId',
|
|
'idp-singleSignOnService.url',
|
|
'idp-x509cert',
|
|
'security-authnRequestsSigned',
|
|
'security-logoutRequestSigned',
|
|
'security-logoutResponseSigned',
|
|
'security-wantMessagesSigned',
|
|
'security-wantAssertionsSigned',
|
|
'general-idp0_display_name',
|
|
'type',
|
|
'sp-x509cert',
|
|
'idp-singleLogoutService.url']
|
|
for cfg in cfg_list:
|
|
self.pg.update("""DELETE FROM "oc_appconfig" WHERE appid = 'user_saml' AND configkey = '%s'""" % (cfg))
|
|
|
|
def add_keycloak_nextcloud_saml(self):
|
|
client={"id" : "bef873f0-2079-4876-8657-067de27d01b7",
|
|
"name": "nextcloud",
|
|
"description": "nextcloud",
|
|
"clientId" : "https://nextcloud."+os.environ['DOMAIN']+"/apps/user_saml/saml/metadata",
|
|
"surrogateAuthRequired" : False,
|
|
"enabled" : True,
|
|
"alwaysDisplayInConsole" : False,
|
|
"clientAuthenticatorType" : "client-secret",
|
|
"redirectUris" : [ "https://nextcloud."+os.environ['DOMAIN']+"/apps/user_saml/saml/acs" ],
|
|
"webOrigins" : [ "https://nextcloud."+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.assertion.signature" : True,
|
|
"saml.force.post.binding" : True,
|
|
"saml_assertion_consumer_url_post" : "https://nextcloud."+os.environ['DOMAIN']+"/apps/user_saml/saml/acs",
|
|
"saml.server.signature" : True,
|
|
"saml.server.signature.keyinfo.ext" : False,
|
|
"saml.signing.certificate" : app['config']['PUBLIC_CERT'],
|
|
"saml_single_logout_service_url_redirect" : "https://nextcloud."+os.environ['DOMAIN']+"/apps/user_saml/saml/sls",
|
|
"saml.signature.algorithm" : "RSA_SHA256",
|
|
"saml_force_name_id_format" : False,
|
|
"saml.client.signature" : False,
|
|
"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" : "e8e4acff-da2b-46aa-8bdb-ba42171671d6",
|
|
"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" : "28206b59-757b-4e3c-81cb-0b6053b1fd3d",
|
|
"name" : "email",
|
|
"protocol" : "saml",
|
|
"protocolMapper" : "saml-user-property-mapper",
|
|
"consentRequired" : False,
|
|
"config" : {
|
|
"attribute.nameformat" : "Basic",
|
|
"user.attribute" : "email",
|
|
"friendly.name" : "email",
|
|
"attribute.name" : "email"
|
|
}
|
|
}, {
|
|
"id" : "e51e04b9-f71a-42de-819e-dd9285246ada",
|
|
"name" : "Roles",
|
|
"protocol" : "saml",
|
|
"protocolMapper" : "saml-role-list-mapper",
|
|
"consentRequired" : False,
|
|
"config" : {
|
|
"single" : True,
|
|
"attribute.nameformat" : "Basic",
|
|
"friendly.name" : "Roles",
|
|
"attribute.name" : "Roles"
|
|
}
|
|
} ],
|
|
"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
|
|
|
|
n=NextcloudSaml() |