Branch 'pykolab-0.6' - bin/kolab_smtp_access_policy.py conf/kolab.conf pykolab/utils.py

Jeroen van Meeuwen vanmeeuwen at kolabsys.com
Tue Feb 11 14:31:22 CET 2014


 bin/kolab_smtp_access_policy.py |  126 +++++++++++++++++++++++++++++++++++++---
 conf/kolab.conf                 |   23 ++++++-
 pykolab/utils.py                |   24 +++++++
 3 files changed, 163 insertions(+), 10 deletions(-)

New commits:
commit 372707888d593f737f63114c94ad8672327c5133
Author: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen at kolabsys.com>
Date:   Tue Feb 11 14:30:14 2014 +0100

    Add new settings to control when (under what circumstances) a Sender:, X-Sender: or even an obscured X-Authenticated-As: header is prepended to email submitted through Kolab.

diff --git a/bin/kolab_smtp_access_policy.py b/bin/kolab_smtp_access_policy.py
index 304ab85..935fc6e 100755
--- a/bin/kolab_smtp_access_policy.py
+++ b/bin/kolab_smtp_access_policy.py
@@ -1333,14 +1333,124 @@ def hold(message, policy_request=None):
 def permit(message, policy_request=None):
     log.info(_("Returning action PERMIT: %s") % (message))
 
-    if hasattr(policy_request, 'sasl_username'):
-        sender = conf.get('kolab_smtp_access_policy', 'sender_header')
-        if utils.true_or_false(sender):
-            print "action=PREPEND Sender: %s" % (policy_request.sasl_username)
-
-        xsender = conf.get('kolab_smtp_access_policy', 'xsender_header')
-        if utils.true_or_false(xsender):
-            print "action=PREPEND X-Sender: %s" % (policy_request.sasl_username)
+    # If we have no policy request, we have been called for a reason,
+    # and everything relevant has been figured out already.
+    if policy_request == None:
+        print "action=PERMIT\n\n"
+        sys.exit(0)
+
+    # If the user is not authenticated, there's no reason to do
+    # extra checks here -- to have been performed already.
+    if not hasattr(policy_request, 'sasl_username'):
+        print "action=PERMIT\n\n"
+        sys.exit(0)
+
+    # Same here.
+    if policy_request.sasl_username == None:
+        print "action=PERMIT\n\n"
+        sys.exit(0)
+
+    delegate_sender_header = None
+    alias_sender_header = None
+
+    # If the sender is a delegate of the envelope sender address, take into
+    # account the preferred domain policy for appending the Sender and/or
+    # X-Sender headers.
+    #
+    # Note that a delegatee by very definition is not using an alias.
+    #
+    if policy_request.sasl_user_is_delegate:
+        # Domain-specific setting?
+        if not policy_request.sender_domain == None:
+            delegate_sender_header = conf.get(policy_request.sender_domain, 'delegate_sender_header')
+
+        # Global setting?
+        if delegate_sender_header == None:
+            delegate_sender_header = conf.get('kolab_smtp_access_policy', 'delegate_sender_header')
+
+        # Default
+        if delegate_sender_header == None:
+            delegate_sender_header = True
+
+    # If the sender is using an alias as the envelope sender address, take
+    # into account the preferred domain policy for appending the Sender
+    # and/or X-Sender headers.
+    elif policy_requiest.sasl_user_uses_alias:
+        # Domain-specific setting?
+        if not policy_request.sender_domain == None:
+            alias_sender_header = conf.get(policy_request.sender_domain, 'alias_sender_header')
+
+        # Global setting?
+        if alias_sender_header == None:
+            alias_sender_header = conf.get('kolab_smtp_access_policy', 'alias_sender_header')
+
+        # Default
+        if alias_sender_header == None:
+            alias_sender_header = True
+
+    # Make the values booleans
+    delegate_sender_header = utils.true_or_false(delegate_sender_header)
+    alias_sender_header = utils.true_or_false(alias_sender_header)
+
+    # Do we use a (simple) encryption key to obscure the headers' contents?
+    # Note that using an encryption key voids the actual use of proper Sender
+    # and X-Sender headers such as they could be interpreted by a client
+    # application.
+    enc_key = conf.get(policy_request.sender_domain, 'sender_header_enc_key')
+    if enc_key == None:
+        enc_key = conf.get('kolab_smtp_access_policy', 'sender_header_enc_key')
+
+    sender_header = None
+    xsender_header = None
+
+    if delegate_sender_header or alias_sender_header:
+        # Domain specific?
+        sender_header = conf.get(policy_request.sender_domain, 'sender_header')
+
+        # Global setting?
+        if sender_header == None:
+            sender_header = conf.get('kolab_smtp_access_policy', 'sender_header')
+
+        # Default
+        if sender_header == None:
+            sender_header = True
+
+        # Domain specific?
+        xsender_header = conf.get(policy_request.sender_domain, 'xsender_header')
+
+        # Global setting?
+        if xsender_header == None:
+            xsender_header = conf.get('kolab_smtp_access_policy', 'xsender_header')
+
+        # Default
+        if xsender_header == None:
+            xsender_header = True
+
+    # Note that if the user is not a delegatee, and not using an alias, the sender
+    # address is the envelope sender address, and the defaults for sender_header
+    # and xsender_header being None, ultimately evaluating to False seems
+    # appropriate.
+
+    # Make the values booleans
+    sender_header = utils.true_or_false(sender_header)
+    xsender_header = utils.true_or_false(xsender_header)
+
+    if sender_header or xsender_header:
+        # Do the encoding, if any
+        if not enc_key == None:
+            header = 'X-Authenticated-As'
+            xheader = None
+            sender = utils.encode(enc_key, policy_request.sasl_username)
+        else:
+            header = 'Sender'
+            xheader = 'X-Sender'
+            sender = policy_request.sasl_username
+
+        if sender_header:
+            print "action=PREPEND %s: %s" % (header, sender)
+
+        if xsender_header and not xheader == None:
+            print "action=PREPEND %s: %s" % (xheader, sender)
 
     print "action=PERMIT\n\n"
     sys.exit(0)
diff --git a/conf/kolab.conf b/conf/kolab.conf
index 8c36605..2f8ea2b 100644
--- a/conf/kolab.conf
+++ b/conf/kolab.conf
@@ -279,12 +279,31 @@ cache_retention = 86400
 ; list.
 address_search_attrs = mail, alias
 
-; Prepend the Sender: header?
+; Prepend the Sender: and/or X-Sender header(s) if the user authenticated is a
+; designated delegatee of the envelope sender address?
+delegate_sender_header = True
+
+; Prepend the Sender: and/or X-Sender header(s) if the user authenticated
+; is using an envelope sender address that is a secondary recipient email
+; address (attached to the object entry) of the user authenticated?
+alias_sender_header = True
+
+; Prepend the Sender: header? Only relevant if delegate_sender_header or
+; alias_sender_header is set to True.
 sender_header = True
 
-; Prepend the X-Sender: header?
+; Prepend the X-Sender: header? Only relevant if delegate_sender_header or
+; alias_sender_header is set to True.
 xsender_header = True
 
+; "Encrypt" -- read, "obscure" -- the contents of the 'Sender:' and/or
+; 'X-Sender:' header(s). Note that this invalidates client's use of the header
+; value, and therefore replaces both headers with 'X-Authenticated-As'.
+;
+; Example: 'vanmeeuwen at kolabsys.com' becomes '6crb3dHK6ODS3qzQ4tXO0t_e5pfQ39k='
+;
+; sender_header_enc_key = 'simple'
+
 ; Allow hosts in these networks to submit messages with empty envelope senders,
 ; such as web-clients responding to MDN requests.
 empty_sender_hosts = 3.2.1.0/24, 6.6.6.0/24
diff --git a/pykolab/utils.py b/pykolab/utils.py
index 5cba8f9..b7ff468 100644
--- a/pykolab/utils.py
+++ b/pykolab/utils.py
@@ -17,6 +17,7 @@
 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #
 
+import base64
 import getpass
 import grp
 import os
@@ -182,6 +183,29 @@ def ask_menu(question, options={}, default=''):
 
     return answer
 
+def decode(key, enc):
+    if key == None:
+        return enc
+
+    dec = []
+    enc = base64.urlsafe_b64decode(enc)
+    for i in range(len(enc)):
+        key_c = key[i % len(key)]
+        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
+        dec.append(dec_c)
+    return "".join(dec)
+
+def encode(key, clear):
+    if key == None:
+        return clear
+
+    enc = []
+    for i in range(len(clear)):
+        key_c = key[i % len(key)]
+        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
+        enc.append(enc_c)
+    return base64.urlsafe_b64encode("".join(enc))
+
 def ensure_directory(_dir, _user='root', _group='root'):
     if not os.path.isdir(_dir):
         os.makedirs(_dir)




More information about the commits mailing list