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