Files
seafile-sso/seafile-sso.py
2022-05-23 19:15:24 -04:00

156 lines
7.0 KiB
Python

#!/usr/bin/env python
from ldap3 import Connection, Server, ANONYMOUS, SIMPLE, SYNC, ASYNC, core
from getpass import getpass
import configparser
import logging
import argparse
import os
import requests
import urllib3
import json
import mysql.connector
def request(resource, seafileURL, seafileToken, method='GET', data=None, dataIsJson=True):
if data is None:
httpHeaders = {'Accept': 'application/json; charset=utf-8; indent=4', 'Authorization': 'Token {0}'.format(seafileToken)}
data = ''
else:
if dataIsJson:
data = json.dumps(data)
httpHeaders = {'Content-type': 'application/json', 'Accept': 'application/json; charset=utf-8; indent=4', 'Authorization': 'Token {0}'.format(seafileToken)}
else:
httpHeaders = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'application/json; charset=utf-8; indent=4', 'Authorization': 'Token {0}'.format(seafileToken)}
url = '{0}/api/v2.1/{1}'.format(seafileURL, resource)
logger.debug('Request URL: {0}'.format(url))
logger.debug('Request Method: {0}'.format(method))
logger.debug('Request Headers: {0}'.format(httpHeaders))
logger.debug('Request Data: {0}'.format(data))
r = requests.request(
method,
url,
data = data,
headers = httpHeaders,
)
logger.debug('Response: {0}'.format(r))
logger.debug('Request Status Code: {0}'.format(r.status_code))
if r.ok:
try:
logger.debug('Request Returned JSON: {0}'.format(r.json()))
return {'ok': r.ok, 'status_code': r.status_code, 'response': r.json()}
except:
logger.debug('Request Returned Text: {0}'.format(r.text))
return {'ok': r.ok, 'status_code': r.status_code, 'response': r.text}
raise ValueError(r)
#def
parser = argparse.ArgumentParser(description='Sync LDAP with Seafile')
parser.add_argument('-v', '--verbose', action='store_true', help='increase log level to debug')
args = parser.parse_args()
logger = logging.getLogger(__name__)
logFormatter = logging.Formatter('%(asctime)s - [%(levelname)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
logger.setLevel(logging.INFO)
if args.verbose:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
#fileHandler = logging.FileHandler("/tmp/seafile-ldap.log")
#fileHandler.setFormatter(logFormatter)
#logger.addHandler(fileHandler)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
logger.addHandler(consoleHandler)
# get directory of script
cwd = os.path.dirname(os.path.realpath(__file__))
configPath = os.path.join(cwd, 'config.ini')
# import the config file
logger.debug("Starting to read the config.ini file.")
logger.debug("Using file {0}.".format(configPath))
if os.path.exists(configPath):
config = configparser.ConfigParser()
config.read(configPath)
else:
logger.critical("Unable to find/read config file. Please ensure the config.ini is in the same directory as this script and readable.")
exit(1)
seafileToken = config['Seafile']['token']
ccnetPath = config['Seafile']['ccnetPath']
adminEmail = config['Seafile']['adminEmail']
logger.debug("Seafile Token: {0}".format(seafileToken))
logger.debug("Seafile ccnet.conf File Path: {0}".format(ccnetPath))
logger.debug("Seafile Admin Email: {0}".format(adminEmail))
logger.debug("Finished reading the config.ini file.")
logger.debug("Starting to read the ccnet.conf file.")
if os.path.exists(ccnetPath):
ccnetConfig = configparser.ConfigParser()
ccnetConfig.read(ccnetPath)
else:
logger.critical("Unable to find/read ccnet.conf file. Please ensure the ccnet.conf path is correct in the config.ini.")
exit(2)
# Seafile url
seafileURL = ccnetConfig['General']['SERVICE_URL']
# ldap Config
ldapHost = ccnetConfig['LDAP']['HOST']
#ldapPort = ccnetConfig['LDAP SERVER'].getint('port')
#ldapSSL = ccnetConfig['LDAP SERVER'].getboolean('ssl')
ldapBase = ccnetConfig['LDAP']['BASE']
ldapUserDN = ccnetConfig['LDAP']['USER_DN']
ldapUserPassword = ccnetConfig['LDAP']['PASSWORD']
ldapFilter = ccnetConfig['LDAP']['FILTER']
logger.debug("LDAP Host: {0}, LDAP Base: {1}, LDAP User DN: {2}, LDAP Filter: {3}".format(ldapHost, ldapBase, ldapUserDN, ldapFilter))
logger.debug("Finished reading the ccnet.conf file.")
# setup the server
ldapServer = Server(ldapHost)
logger.debug("Setup LDAP server connection uri: {0}".format(ldapServer))
try:
ldap = Connection(ldapServer, ldapUserDN, ldapUserPassword, auto_bind=True)
except core.exceptions.LDAPBindError as e:
logger.critical("LDAP Bind Failed. {0}".format(e))
exit()
logger.debug("Bind successful.")
# get seafile users and loop through and check group membership and disable or not
logger.debug("Starting query for users in Seafile")
seafileUsers = request('admin/users/', seafileURL, seafileToken)['response']['data']
# need to substract one from the len as the admin account is in the list
logger.debug("Found {0} Seafile users".format(len(seafileUsers)-1))
for seafileUser in seafileUsers:
if seafileUser['email'] == adminEmail:
continue
else:
logger.debug("User: {0} - Active: {1}".format(seafileUser['email'], bool(seafileUser['is_active'])))
logger.debug("Checking if {0} user has an email, is active, and is in the seafile group")
ldap.search(ldapBase, '(&(mail={0})(!(userAccountControl:1.2.840.113556.1.4.803:=2))({1}))'.format(seafileUser['email'], ldapFilter), attributes=['*'])
count = len(ldap.entries)
logger.debug("Found {0} LDAP user.".format(count))
if count == 0:
logger.debug("User {0} doesn't have an email, isn't active, or isn't in the seafile group, disabling in seafile...".format(seafileUser['email']))
if not seafileUser['is_active']:
logger.debug("User {0} is already disabled in Seafile".format(seafileUser['email']))
continue
disableUserinSeafile = request('admin/users/{0}/'.format(seafileUser['email']), seafileURL, seafileToken, "PUT", {"is_active": "false"})['response']
if not disableUserinSeafile['is_active']:
logger.info("User {0} was set to disabled in Seafile".format(seafileUser['email']))
else:
logger.error("There was an error setting user {0} to disabled in Seafile".format(seafileUser['email']))
else:
logger.debug("User {0} has an email, is active, and is in the seafile group".format(seafileUser['email']))
if seafileUser['is_active']:
logger.debug("User {0} is already active in Seafile".format(seafileUser['email']))
continue
ActiveUserinSeafile = request('admin/users/{0}/'.format(seafileUser['email']), seafileURL, seafileToken, "PUT", {"is_active": "true"})['response']
if not ActiveUserinSeafile['is_active']:
logger.info("User {0} was set to active in Seafile".format(seafileUser['email']))
else:
logger.error("There was an error setting user {0} to active in Seafile".format(seafileUser['email'])