#!/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 def request(resource, seafile, method='GET', data=None): if data is None: data = '' else: data = json.dumps(data) url = '{0}/api/v2.1/{1}'.format(seafile['url'], resource) logger.debug('Request URL: {}'.format(url)) logger.debug('Request Data: {}'.format(data)) r = requests.request( method, url, data=data, headers={'Accept': 'application/json; indent=4', 'Authorization': 'Token {0}'.format(seafile['token'])}, ) logger.debug('Request Status Code: {}'.format(r.status_code)) if r.ok: try: logger.debug('Request Returned JSON: {}'.format(r.json())) return {'ok': r.ok, 'status_code': r.status_code, 'response': r.json()} except: logger.debug('Request Returned Text: {}'.format(r.text)) return {'ok': r.ok, 'status_code': r.status_code, 'response': r.text} raise ValueError(r) parser = argparse.ArgumentParser(description='Sync LDAP with Seafile') #group = parser.add_mutually_exclusive_group() #group.add_argument('-e', '--encrypt', action='store_true', help='encrypt') #group.add_argument('-d', '--decrypt', action='store_true', help='decrypt') #parser.add_argument('-t', '--text', type=str, help='text to encrypt/decrypt') #group2 = parser.add_mutually_exclusive_group() #group2.add_argument('-t', '--text', type=str, help='text to encrypt/decrypt') #group2.add_argument('-f', '--file', type=str, help='file to encrypt/decrypt, will create a .pynacl file when encrypting, and requires .pynacl file to decrypt') 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.") 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'] logger.debug("Seafile Token: {0}".format(seafileToken)) logger.debug("Seafile ccnet.conf File Path: {0}".format(ccnetPath)) 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'] # DB config dbEngine = config['Database']['ENGINE'] dbHost = config['Database']['HOST'] dbPort = config['Database'].getint('PORT') dbUser = config['Database']['USER'] dbPassword = config['Database']['PASSWD'] dbName = config['Database']['DB'] dbCharset = config['Database']['CONNECTION_CHARSET'] logger.debug("DB Engine: {0}, DB Host: {1}, DB Port: {2}, DB User: {3}, DB Name: {4}, DB Connection Charset: {5}".format(dbEngine, dbHost, dbPort, dbUser, dbName, dbCharset)) # ldap Config ldapServer = config['LDAP']['HOST'] #ldapPort = config['LDAP SERVER'].getint('port') #ldapSSL = config['LDAP SERVER'].getboolean('ssl') ldapBase = config['LDAP']['BASE'] ldapUserDN = config['LDAP']['USER_DN'] ldapUserPassword = config['LDAP']['PASSWORD'] ldapFilter = config['LDAP']['FILTER'] logger.debug("LDAP Server: {0}, LDAP Base: {1}, LDAP User DN: {2}, LDAP Filter: {3}".format(ldapServer, ldapBase, ldapUserDN, ldapFilter)) logger.debug("Finished reading the config.") # setup the server server = Server(serverDNS, port=serverPort, use_ssl=serverSSL) logger.debug("Setup server connection uri: {0}".format(server)) try: ldap = Connection(server, bindAccount, bindPassword, auto_bind=True) except core.exceptions.LDAPBindError as e: logger.critical("LDAP Bind Failed. {0}".format(e)) exit() logger.debug("Bind successful.") logger.debug("Searching for users that have a email address, are enabled, and in the {} group.".format(config['LDAP SERVER']['seafileGroupDN'])) ldap.search(config['LDAP SERVER']['groupBaseDN'], '(&(mail=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(memberof={0}))'.format(config['LDAP SERVER']['seafileGroupDN']), attributes=['*']) logger.debug("Found {0} users.".format(len(ldap.entries))) ADusers = ldap.entries for user in ADusers: logger.debug("User: {0} - Email: {1} - UserDN: {2}".format(user.name, user.mail, user.distinguishedName)) seafileUsers = request('admin/search-user/?query=@johnhgaunt.com', seafile)['response']['user_list'] for user in seafileUsers: logger.debug("User: {0} - Email: {1} - isActive: {2}".format(user['name'], user['email'], user['is_active'])) #print(ldap.entries[0].distinguishedName) exit() #Create a connection object, and bind with the given DN and password. try: conn = Connection(server, bindAccount, bindPassword, auto_bind=True) print('LDAP Bind Successful.') # Perform a search for a pre-defined criteria. # Mention the search filter / filter type and attributes. conn.search('CN=Users,dc=home,dc=johnhgaunt,dc=com', '(&(mail=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(memberOf=CN=Seafile,CN=Users,DC=home,DC=johnhgaunt,DC=com))') # Print the resulting entries. for entry in conn.entries: print(entry) except core.exceptions.LDAPBindError as e: #If the LDAP bind failed for reasons such as authentication failure. print('LDAP Bind Failed: ', e) # sync ad users with seafile, if disabled or deleted ad user, disable in seafile # get ad groups and import them into seafile # loop through each group and list members # compare members to users in seafile group # add users to group if missing and in the seafile group # remove members in not in group or seafile group # remove seafile groups if ad group is removed ldap.search(config['LDAP SERVER']['groupBaseDN'], '(objectClass=group)', attributes=['*']) #print(ldap.entries) for group in ldap.entries: try: if group.member: logger.debug("{0}".format(group.name)) finally: continue