diff --git a/README.md b/README.md index 0150878..838f88a 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ +### EgoServ-LDAP + +This is in a very early development stage, and so is the upstream EgoServ plugin. + +Goals: + - Extend EgoServ to sync user details and modifications with an external backend (LDAP) + - Extend EgoServ to modify user attributes beyond IRC + - Make EgoServ attractive to federated environments + - Allow for easier permission management through LDAP group assignments + +---- +### Original README.md: Suite of tools to help Network Operators run their ErgoIRCd nets diff --git a/__pycache__/__init__.cpython-38.pyc b/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..6b42cbf Binary files /dev/null and b/__pycache__/__init__.cpython-38.pyc differ diff --git a/__pycache__/config.cpython-38.pyc b/__pycache__/config.cpython-38.pyc new file mode 100644 index 0000000..aa4ebab Binary files /dev/null and b/__pycache__/config.cpython-38.pyc differ diff --git a/__pycache__/plugin.cpython-38.pyc b/__pycache__/plugin.cpython-38.pyc new file mode 100644 index 0000000..fa865e6 Binary files /dev/null and b/__pycache__/plugin.cpython-38.pyc differ diff --git a/config.py b/config.py index 65b95ee..e71c657 100644 --- a/config.py +++ b/config.py @@ -52,5 +52,59 @@ EgoServ = conf.registerPlugin('EgoServ') # conf.registerGlobalValue(EgoServ, 'someConfigVariableName', # registry.Boolean(False, _("""Help for someConfigVariableName."""))) +conf.registerGroup(EgoServ, 'ldap') + +conf.registerGlobalValue(EgoServ.ldap, 'host', +registry.String('', +""" +LDAP server URI to connect to. +Example: ` ldaps://example.com:636 ` +Plain LDAP is not supported. +""" +, private=True +)) +conf.registerGlobalValue(EgoServ.ldap, 'secure', +registry.Boolean('true', +""" +true: Strict TLS certificate checking +false: Certificates will be COMPLETELY ignored +Please keep this `true` in any environment that is not a local test instance. +If you don't have a working CA in your production LDAP infrastructure, unload this plugin. +""" +, private=True +)) +conf.registerGlobalValue(EgoServ.ldap, 'basedn', +registry.String('', +""" +Base DN for all queries +""" +, private=True +)) +conf.registerGlobalValue(EgoServ.ldap, 'binddn', +registry.String('', +""" +Unprivileged DN to bind to. +Ensure the ACIs are correct. +""" +, private=True +)) +conf.registerGlobalValue(EgoServ.ldap, 'bindpw', +registry.String('', +""" +Password for the DN to bind to. +""" +, private=True +)) + +conf.registerGroup(EgoServ, 'groups') + +conf.registerGlobalValue(EgoServ.groups, 'admins', +registry.String('', +""" +Group DN to grant the highest privileges to. +Only tested with ` CN= `. +""" +, private=True +)) # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/plugin.py b/plugin.py index 289d60d..cb33a19 100644 --- a/plugin.py +++ b/plugin.py @@ -28,6 +28,7 @@ ### +import ldap from supybot import utils, plugins, ircutils, callbacks, irclib, ircmsgs, conf, world, log from supybot.commands import * try: @@ -50,7 +51,8 @@ class EgoServ(callbacks.Plugin): # OPER # This should check if it has OPER right away - + + # PERMS # This is designed to be a single network ErgoIRCd administrative bot # So maybe I just set default perms to owner! @@ -93,11 +95,53 @@ class EgoServ(callbacks.Plugin): 1: No new connections except from localhost or other trusted IPs """ + arg = [] arg.append(level) irc.sendMsg(msg=ircmsgs.IrcMsg(command='DEFCON', args=arg)) irc.replySuccess(f'Setting DEFCON level to {arg}! Good Luck!') + # QUERY + @wrap(['nick']) + def query(self, irc, msg, args, nick): + """ + Dumps shit. + """ + arg = [nick] + searchFilter = "(&(uid=" + nick + "*)(objectClass=nsPerson))" + searchAttribute = ["uid","uidNumber","nsAccountLock"] + searchScope = ldap.SCOPE_SUBTREE + host = self.registryValue('ldap.host') + binddn = self.registryValue('ldap.binddn') + pw = self.registryValue('ldap.bindpw') + basedn = self.registryValue('ldap.basedn') + secure = self.registryValue('ldap.secure') + if secure == False: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + else: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD) + l = ldap.initialize(host) + try: + ldap.set_option(ldap.OPT_X_TLS_NEWCTX, 0) + l.protocol_version = ldap.VERSION3 + l.simple_bind_s(binddn, pw) + except ldap.INVALID_CREDENTIALS: + print("Invalid LDAP credentials") + irc.reply("Internal error.") + except ldap.LDAPError: + print(ldap.LDAPError()) + irc.reply("Error output sent to console.") + try: + ldap_result_id = l.search(basedn, searchScope, searchFilter, searchAttribute) + result_set = [] + res = l.search_s(basedn, searchScope, searchFilter, searchAttribute) + print(res) + irc.reply(res) + except ldap.LDAPError: + print(ldap.LDAPError) + irc.reply("Error output sent to console.") + + l.unbind_s() # KILL @wrap(['nick', optional('something')]) @@ -287,7 +331,49 @@ class EgoServ(callbacks.Plugin): sets a 's . must be in the format 'hello.world' """ + arg = [nick] + searchFilter = "(&(uid=" + nick + "*)(objectClass=nsPerson))" + nickdn = "CN=" + nick + ",ou=lab_users,dc=lab,dc=local" + searchAttribute = ["uid"] + searchScope = ldap.SCOPE_SUBTREE + host = self.registryValue('ldap.host') + binddn = self.registryValue('ldap.binddn') + pw = self.registryValue('ldap.bindpw') + basedn = self.registryValue('ldap.basedn') + secure = self.registryValue('ldap.secure') + attr_vhost = 'displayName' + if secure == False: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) + else: + ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD) + l = ldap.initialize(host) + try: + ldap.set_option(ldap.OPT_X_TLS_NEWCTX, 0) + l.protocol_version = ldap.VERSION3 + l.simple_bind_s(binddn, pw) + except ldap.INVALID_CREDENTIALS: + print("Invalid LDAP credentials") + irc.reply("Internal error.") + except ldap.LDAPError: + print(ldap.LDAPError()) + irc.reply("Error output sent to console.") + try: + #this is not yet operational + #attrmod = [( ldap.MOD_REPLACE, attr_vhost, vhost)] + l.modify_s(nickdn, [( ldap.MOD_REPLACE, attr_vhost, vhost)]) + + print("Modifying " + nickdn + ": setting " + attr_vhost + " to" + vhost) + irc.reply("Attribute updated.") + except ldap.LDAPError: + print(ldap.LDAPError) + irc.reply("Error output sent to console.") + + l.unbind_s() + + label = ircutils.makeLabel() + + irc.queueMsg(ircmsgs.IrcMsg(command='OPER', args=['coffee', '1234567890'])) arg = ['SET'] arg.append(nick)