Commits

Zhang Huangbin committed d70b0aa

Ability to handle policy 'membersAndAllowedOnly'.

Comments (0)

Files changed (3)

+iRedAPD-1.2.4:
+    * Ability to handle policy 'membersAndAllowedOnly'.
+
 iRedAPD-1.2.3:
     * Change default action to 'DUNNO', so that we won't miss any email while
       incorrect config.
 
 # Author: Zhang Huangbin <michaelbibby (at) gmail.com>
 
-import os, os.path
+import os
+import os.path
 import sys
 import ConfigParser
 import socket
-import asyncore, asynchat
+import asyncore
+import asynchat
 import logging
 import ldap
 import daemon
 cfg = ConfigParser.SafeConfigParser()
 cfg.read(config_file)
 
+
 class apdChannel(asynchat.async_chat):
     def __init__(self, conn, remoteaddr):
         asynchat.async_chat.__init__(self, conn)
                     action = ACTION_ACCEPT
             except Exception, e:
                 action = ACTION_DEFAULT
-                logging.debug('Error: %s. Use default action instead: %s' % (str(e), str(action)) )
+                logging.debug('Error: %s. Use default action instead: %s' %
+                        (str(e), str(action)))
 
-            logging.info('%s -> %s, %s' % (self.map['sender'], self.map['recipient'], action))
+            logging.info('%s -> %s, %s' %
+                    (self.map['sender'], self.map['recipient'], action))
             self.push('action=' + action)
             self.push('')
             asynchat.async_chat.handle_close(self)
             asynchat.async_chat.handle_close(self)
             logging.debug("Connection closed")
 
+
 class apdSocket(asyncore.dispatcher):
     def __init__(self, localaddr):
         asyncore.dispatcher.__init__(self)
         self.bind(localaddr)
         self.listen(5)
         ip, port = localaddr
-        logging.info("Starting iredapd (v%s, pid: %d), listening on %s:%s." % (__version__, os.getpid(), ip, str(port)))
-
+        logging.info("Starting iredapd (v%s, pid: %d), listening on %s:%s." %
+                (__version__, os.getpid(), ip, str(port)))
 
     def handle_accept(self):
         conn, remoteaddr = self.accept()
         channel = apdChannel(conn, remoteaddr)
 
+
 class LDAPModeler:
     def __init__(self):
         # Read LDAP server settings.
                 self.conn.bind_s(self.binddn, self.bindpw)
                 logging.debug('LDAP bind success.')
             except ldap.INVALID_CREDENTIALS:
-                logging.error('LDAP bind failed, incorrect bind dn or password.')
+                logging.error('LDAP bind failed: incorrect bind dn or password.')
                 sys.exit()
             except Exception, e:
                 logging.error('LDAP bind failed: %s.' % str(e))
         try:
             cfg.set('ldap', "recipient", recipient)
         except Exception, e:
-            logging.error("""Error while replacing 'recipient': %s""" % (str(e)) )
+            logging.error("""Error while replacing 'recipient': %s""" % (str(e)))
 
         # Search mail list object.
         searchBasedn = 'mail=%s,ou=Groups,domainName=%s,%s' % (recipient, recipient.split('@')[1], self.baseDN)
                     return ACTION_REJECT
 
     def handle_data(self, map):
-        if map.has_key("sender") and map.has_key("recipient"):
+        if 'sender' in map.keys() and 'recipient' in map.keys():
 
             # Get plugin module name and convert plugin list to python list type.
             self.plugins = cfg.get('ldap', 'plugins', '')
-            self.plugins = [ v.strip() for v in self.plugins.split(',') ]
+            self.plugins = [v.strip() for v in self.plugins.split(',')]
 
             if len(self.plugins) > 0:
 
         else:
             return ACTION_DEFER
 
+
 def main():
     # Chroot in current directory.
     try:

src/plugins/maillist_access_policy.py

 
 # Author: Zhang Huangbin <michaelbibby (at) gmail.com>
 
+# ----------------------------------------------------------------------------
+# This plugin is used for mail deliver restriction.
+# ----------------------------------------------------------------------------
+
 import sys
 
 ACTION_REJECT = 'REJECT Not Authorized'
 def __get_allowed_senders(ldapConn, ldapBaseDn, listDn, sender, recipient, policy,):
     """return search_result_list_based_on_access_policy"""
 
+    basedn = ldapBaseDn
+    searchScope = 2     # Use SCOPE_BASE to improve performance.
+
     # Set search base dn, scope, filter and attribute list based on access policy.
     if policy == 'membersonly':
-        basedn = ldapBaseDn
-        searchScope = 2     # ldap.SCOPE_SUBTREE
         # Filter used to get domain members.
         searchFilter = "(&(|(objectclass=mailUser)(objectClass=mailExternalUser))(accountStatus=active)(memberOfGroup=%s))" % (recipient, )
-        searchAttr = 'mail'
-    else:
+        searchAttr = ['mail']
+    elif policy == 'allowedonly':
         basedn = listDn
         searchScope = 0     # Use SCOPE_BASE to improve performance.
         # Filter used to get domain moderators.
         searchFilter = "(&(objectclass=mailList)(mail=%s))" % (recipient, )
-        searchAttr = 'listAllowedUser'
+        searchAttr = ['listAllowedUser']
+    else:
+        # Policy: membersAndAllowedOnly.
+        # Filter used to get both members and moderators.
+        searchFilter = "(|(&(|(objectClass=mailUser)(objectClass=mailExternalUser))(memberOfGroup=%s))(&(objectclass=mailList)(mail=%s)))" % (recipient, recipient, )
+        searchAttr = ['mail', 'listAllowedUser']
 
     try:
-        result = ldapConn.search_s(basedn, searchScope, searchFilter, [searchAttr])
+        result = ldapConn.search_s(basedn, searchScope, searchFilter, searchAttr)
         userList = []
         for obj in result:
-            if obj[1].has_key(searchAttr):
-                # Example of result data:
-                # [('dn', {'listAllowedUser': ['user@domain.ltd']})]
-                # [('dn', {'listAllowedUser': ['user@domain.ltd']})]
-                userList += obj[1][searchAttr]
-            else:
-                pass
+            for k in searchAttr:
+                if k in obj[1].keys():
+                    # Example of result data:
+                    # [('dn', {'listAllowedUser': ['user@domain.ltd']})]
+                    userList += obj[1][k]
+                else:
+                    pass
         return userList
 
     except Exception, e:
         if sender.split('@')[1] == recipient.split('@')[1]: return 'DUNNO'
         else: return ACTION_REJECT
     else:
-        # Handle other access policies: membersOnly, allowedOnly.
+        # Handle other access policies: membersOnly, allowedOnly, membersAndAllowedOnly.
         allowedSenders = __get_allowed_senders(
                 ldapConn=ldapConn,
                 ldapBaseDn=ldapBaseDn,
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.