- [kopano](src/kopano/plugin/movetopublicldap.py) Add sample config file for the kopano-dagent python plugin movetopublicldap.
parent
b9c2529745
commit
6e32101634
|
@ -1,6 +1,7 @@
|
|||
# 1.2.7
|
||||
|
||||
- [kopano](src/kopano/plugin/movetopublicldap.py) Add LDAP support to the [Move to public](https://documentation.kopano.io/kopanocore_administrator_manual/special_kc_configurations.html#move-to-public ) kopano-dagent python plugin.
|
||||
- [kopano](src/kopano/plugin/movetopublicldap.py) Add sample config file for the kopano-dagent python plugin movetopublicldap.
|
||||
|
||||
# 1.2.6
|
||||
|
||||
|
|
16
README.md
16
README.md
|
@ -444,13 +444,13 @@ The [Mobile Device Management](https://documentation.kopano.io/webapp_mdm_manual
|
|||
|
||||
There are two type of stores (folders containing communication elements); private and public stores. There can only be one public store. It is the Kopano dagent that places incoming messages into mail boxes, that is the private and public stores.
|
||||
|
||||
Public folders are managed by the system admin and not by individual users. Users have them mapped automatically. The public folders can be synced via [Exchange ActiveSync (EAS)](https://wiki.z-hub.io/display/ZP/Sharing+folders+and+Read-only) .
|
||||
Public folders are configured by the system admin. Users have them mapped automatically. The shared and public folders can be synced with mobile devices via [Exchange ActiveSync (EAS)](https://wiki.z-hub.io/display/ZP/Sharing+folders+and+Read-only). Each user can manage which shared or public folders to sync with her mobile devices by using the [Mobile Device Management](#mobile-device-management) WebApp plugin.
|
||||
|
||||
With the current Kopano implementation, delivering to the public store is configured separately from normal user management. There is the [move to public](https://documentation.kopano.io/kopanocore_administrator_manual/special_kc_configurations.html#move-to-public) plugin which moves incoming messages to a folder in the public store. It has a static configuration and does not support LDAP lookup.
|
||||
|
||||
### Move to public with LDAP lookup
|
||||
|
||||
The `mlan/kopano` image include a extended version of the move to public plugin which use LDAP lookup, instead of a static file based lookup. When the plugin [move to public with LDAP](src/kopano/plugin/movetopublicldap.py) is enabled, `DAGENT_PLUGINS=movetopublicldap.py`, the kopano dagent will do two LDAP queries. The first is to search for an entry/user with matching email address. The second, introduced with this plugin, is to get the public folder from this entry. If found the message will be delivered to the public folder otherwise it will be delivered to the mailbox of the user.
|
||||
The `mlan/kopano` image include a extended version of the move to public plugin which use LDAP lookup, instead of a static file based lookup. When the plugin [move to public with LDAP](src/kopano/plugin/movetopublicldap.py) is enabled, `DAGENT_PLUGINS=movetopublicldap`, the kopano dagent will do two LDAP queries. The first is to search for an entry/user with matching email address. The second, introduced with this plugin, is to get the public folder from this entry. If found the message will be delivered to the public folder otherwise it will be delivered to the mailbox of the user.
|
||||
|
||||
Lets demonstrate how delivery to a public folder is configured. With this LDAP entry:
|
||||
|
||||
|
@ -466,11 +466,11 @@ mail: public@example.com
|
|||
kopanoAccount: 1
|
||||
kopanoHidden: 1
|
||||
kopanoSharedStoreOnly: 1
|
||||
kopanoResourceType: publicStore:Public Stores/public
|
||||
kopanoResourceType: publicFolder:Public Stores/public
|
||||
```
|
||||
|
||||
messages to `public@example.com` will be delivered to the public store in `Public Stores/public`.
|
||||
The central [attribute](https://documentation.kopano.io/kopanocore_administrator_manual/appendix_b.html#appendix-b-ldap-attribute-description) is `kopanoResourceType: publicStore:Public Stores/public`. It contains a token and a folder name. The token match is case sensitive and there must be a colon `:` separating
|
||||
The central [attribute](https://documentation.kopano.io/kopanocore_administrator_manual/appendix_b.html#appendix-b-ldap-attribute-description) is `kopanoResourceType: publicFolder:Public Stores/public`. It contains a token and a folder name. The token match is case sensitive and there must be a colon `:` separating
|
||||
the token and the public folder name. The folder name can contain space and
|
||||
sub folders, which are distinguished using a forward slash `/`.
|
||||
|
||||
|
@ -479,17 +479,17 @@ The LDAP attribute holding the token and the token itself have the following
|
|||
default values, which can be modified in `/etc/kopano/movetopublicldap.cfg` if desired.
|
||||
|
||||
```yaml
|
||||
ldap_public_store_attribute = kopanoResourceType
|
||||
ldap_public_store_attribute_token = publicStore
|
||||
ldap_public_folder_attribute = kopanoResourceType
|
||||
ldap_public_folder_attribute_token = publicFolder
|
||||
```
|
||||
|
||||
As with other parameters, environment variables can be used to define them: `LDAP_PUBLIC_STORE_ATTRIBUTE=kopanoResourceType` and `LDAP_PUBLIC_STORE_ATTRIBUTE_TOKEN=publicStore`.
|
||||
As with other parameters, environment variables can be used to define them: `LDAP_PUBLIC_FOLDER_ATTRIBUTE=kopanoResourceType` and `LDAP_PUBLIC_FOLDER_ATTRIBUTE_TOKEN=publicFolder`.
|
||||
|
||||
## Shared folders
|
||||
|
||||
Users can share folders when sufficient permission have been granted. When logged into WebApp with an administrative account (`kopanoAdmin: 1`) you can modify the permissions on users shares and folders. Users can then, when logged into WebApp, open the inbox of other users by selecting `Open Shared Mails`.
|
||||
|
||||
The [impersonation](https://wiki.z-hub.io/display/ZP/Impersonation) mechanism allow such shared folders to be synced over [Exchange ActiveSync (EAS)](https://wiki.z-hub.io/display/ZP/Sharing+folders+and+Read-only) too.
|
||||
The [impersonation](https://wiki.z-hub.io/display/ZP/Impersonation) mechanism allow such shared folders to be synced over [Exchange ActiveSync (EAS)](https://wiki.z-hub.io/display/ZP/Sharing+folders+and+Read-only) too. Each user can manage which shared or public folders to sync with her mobile devices by using the [Mobile Device Management](#mobile-device-management) WebApp plugin.
|
||||
|
||||
## Crontab
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ mail: $(LDAP_TEST_PUB)@$(MAIL_DOMAIN)
|
|||
kopanoAccount: 1
|
||||
kopanoHidden: 1
|
||||
kopanoSharedStoreOnly: 1
|
||||
kopanoResourceType: publicStore:Public Stores/public
|
||||
kopanoResourceType: publicFolder:Public Stores/public
|
||||
|
||||
endef
|
||||
export LDIF_ADD_STO
|
||||
|
|
|
@ -27,7 +27,7 @@ services:
|
|||
- LDAP_GROUP_TYPE_ATTRIBUTE_VALUE=${LDAP_GROUPOBJ-posixGroup}
|
||||
- LDAP_GROUPMEMBERS_ATTRIBUTE_TYPE=dn
|
||||
- LDAP_PROPMAP=
|
||||
- DAGENT_PLUGINS=movetopublicldap.py
|
||||
- DAGENT_PLUGINS=movetopublicldap
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE-kopano}
|
||||
- MYSQL_USER=${MYSQL_USER-kopano}
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD-secret}
|
||||
|
|
|
@ -18,7 +18,7 @@ DOCKER_MAN5_DIR=${DOCKER_MAN5_DIR-/usr/share/man/man5/}
|
|||
DOCKER_APPL_SSL_CERT=${DOCKER_APPL_SSL_CERT-$DOCKER_APPL_SSL_DIR/cert.pem}
|
||||
DOCKER_APPL_SSL_KEY=${DOCKER_APPL_SSL_KEY-$DOCKER_APPL_SSL_DIR/priv_key.pem}
|
||||
DOCKER_LDAP_PMAP_FILE=${DOCKER_LDAP_PMAP_FILE-/usr/share/kopano/ldap.propmap.cfg}
|
||||
DOCKER_LDAP_SERVICES=${DOCKER_LDAP_SERVICES-archiver dagent gateway ical ldap movetopublicldap search server spamd spooler}
|
||||
DOCKER_LDAP_SERVICES=${DOCKER_LDAP_SERVICES-archiver dagent gateway ical ldap search server spamd spooler}
|
||||
sqlstate_cfg_file=$DOCKER_CONF_DIR2/backend/sqlstatemachine/config.php
|
||||
zpush_cfg_file=$DOCKER_CONF_DIR2/config.php
|
||||
webapp_cfg_file=$DOCKER_CONF_DIR1/webapp/config.php
|
||||
|
@ -30,7 +30,7 @@ webapp_smime_cfg_file=$DOCKER_CONF_DIR1/webapp/config-smime.php
|
|||
# CLI commands
|
||||
#
|
||||
list_parms() {
|
||||
local services="$DOCKER_LDAP_SERVICES"
|
||||
local services="$DOCKER_LDAP_SERVICES $DAGENT_PLUGINS"
|
||||
[ $# -ge 0 ] && services="$@"
|
||||
for service in $services; do
|
||||
[ $# -ne 1 ] && echo "# $service"
|
||||
|
@ -50,7 +50,7 @@ list_parms() {
|
|||
#
|
||||
kopano_apply_envvars_core() {
|
||||
kopano_enable_envvars_plugin
|
||||
for service in $DOCKER_LDAP_SERVICES; do
|
||||
for service in $DOCKER_LDAP_SERVICES $DAGENT_PLUGINS; do
|
||||
kopano_apply_envvars_cfg $service
|
||||
done
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ kopano_get_envvars_ext() {
|
|||
local vars
|
||||
case $service in
|
||||
movetopublicldap)
|
||||
vars="ldap_public_store_attribute ldap_public_store_attribute_token"
|
||||
vars="ldap_public_folder_attribute ldap_public_folder_attribute_token"
|
||||
;;
|
||||
esac
|
||||
echo $vars | tr "[:lower:]" "[:upper:]" | tr " " "\n" | sort -u
|
||||
|
@ -143,9 +143,16 @@ kopano_enable_envvars_plugin() {
|
|||
for service in dagent spooler; do
|
||||
local envvar=${service^^}_PLUGINS
|
||||
for plugin in ${!envvar}; do
|
||||
dc_log 5 "Enabling ${service} python plugin ${plugin}"
|
||||
ln -sf /usr/share/kopano-${service}/python/plugins/${plugin} /var/lib/kopano/${service}/plugins
|
||||
export ${service^^}_PLUGIN_ENABLED=yes
|
||||
local pyfile=$(find /usr/share/kopano* -name ${plugin}.py)
|
||||
if [ -z "$pyfile" ]; then
|
||||
dc_log 5 "Unable to locate ${service} python plugin ${plugin}"
|
||||
else
|
||||
dc_log 5 "Enabling ${service} python plugin ${plugin}"
|
||||
mkdir -p $DOCKER_CONF_DIR1/${service}
|
||||
ln -sf ${pyfile} $DOCKER_CONF_DIR1/${service}
|
||||
export ${service^^}_PLUGIN_PATH=$DOCKER_CONF_DIR1/${service}
|
||||
export ${service^^}_PLUGIN_ENABLED=yes
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# movetopublicldap.cfg
|
||||
#
|
||||
# Move mail to public ldap configuration
|
||||
#
|
||||
# This configuration file is used by the dagent plugin 'movetopublicldap.py'
|
||||
# The default location is '/etc/kopano/movetopublicldap.cfg'
|
||||
#
|
||||
|
||||
#
|
||||
# The plugin reads two coniguration files.
|
||||
# First it looks for parameters in '/etc/kopano/ldap.cfg' allowing
|
||||
# common conifuration parameters to be kep tin on place.
|
||||
# Second it reads '/etc/kopano/movetopublicldap.cfg'
|
||||
#
|
||||
|
||||
#
|
||||
# Parameters that can be set in both files:
|
||||
#
|
||||
# ldap_uri =
|
||||
# ldap_starttls = no
|
||||
# ldap_search_base =
|
||||
# ldap_bind_user =
|
||||
# ldap_bind_passwd =
|
||||
# ldap_user_unique_attribute = uid
|
||||
#
|
||||
|
||||
#
|
||||
# Parameters that can only be set in ovetopublicldap.cfg:
|
||||
#
|
||||
# ldap_public_folder_attribute = kopanoResourceType
|
||||
# ldap_public_folder_attribute_token = publicFolder
|
||||
#
|
|
@ -8,13 +8,13 @@ store. If folders are missing they will be created.
|
|||
A LDAP entry including:
|
||||
|
||||
kopanoAccount: 1
|
||||
kopanoResourceType: publicStore:<public folder>
|
||||
kopanoResourceType: publicFolder:<public folder>
|
||||
|
||||
will have its email delivered to the public store in <public folder>.
|
||||
The token match is case sensitive and there must be a colon ':' separating
|
||||
the token and the public folder name. The folder name can contain space and
|
||||
sub folders, which are distinguished using forward slash '/'.
|
||||
So if we have 'kopanoResourceType: publicStore:Public Stores/public' emails will
|
||||
So if we have 'kopanoResourceType: publicFolder:Public Stores/public' emails will
|
||||
be delivered to 'Public Folders/Public Stores/public'.
|
||||
|
||||
The parameters in /etc/kopano/ldap.cfg will be used for the LDAP query.
|
||||
|
@ -22,8 +22,8 @@ The LDAP attribute holding the token and the token itself have the following
|
|||
default values, which can be modified in /etc/kopano/movetopublicldap.cfg
|
||||
if desired.
|
||||
|
||||
ldap_public_store_attribute = kopanoResourceType
|
||||
ldap_public_store_attribute_token = publicStore
|
||||
ldap_public_folder_attribute = kopanoResourceType
|
||||
ldap_public_folder_attribute_token = publicFolder
|
||||
|
||||
"""
|
||||
from sys import hexversion
|
||||
|
@ -37,6 +37,7 @@ from plugintemplates import IMapiDAgentPlugin, MP_CONTINUE, MP_STOP_SUCCESS
|
|||
from zconfig import ZConfigParser
|
||||
import configparser
|
||||
import ldap
|
||||
import os.path
|
||||
|
||||
class KConfigParser(ZConfigParser):
|
||||
""" Extends zconfig.ZConfigParser to also allow !directive in cfg files """
|
||||
|
@ -55,12 +56,13 @@ class MoveToPublic(IMapiDAgentPlugin):
|
|||
|
||||
DEFAULTCONFIG = {
|
||||
'ldap_uri': None,
|
||||
'ldap_starttls': "no",
|
||||
'ldap_search_base': None,
|
||||
'ldap_bind_user': None,
|
||||
'ldap_bind_passwd': None,
|
||||
'ldap_user_unique_attribute': "uid",
|
||||
'ldap_public_store_attribute': "kopanoResourceType",
|
||||
'ldap_public_store_attribute_token': "publicStore"
|
||||
'ldap_public_folder_attribute': "kopanoResourceType",
|
||||
'ldap_public_folder_attribute_token': "publicFolder"
|
||||
}
|
||||
|
||||
def __init__(self, logger):
|
||||
|
@ -72,34 +74,40 @@ class MoveToPublic(IMapiDAgentPlugin):
|
|||
options = [opt.split('_', 1)[1] for opt in defaultconfig.keys()]
|
||||
config = None
|
||||
for configfile in configfiles:
|
||||
if not config:
|
||||
config = KConfigParser(configfile, defaultconfig)
|
||||
if os.path.isfile(configfile):
|
||||
self.logger.logDebug("*--- Reading file {}".format(configfile))
|
||||
if not config:
|
||||
config = KConfigParser(configfile, defaultconfig)
|
||||
else:
|
||||
config = KConfigParser(configfile, config.options())
|
||||
else:
|
||||
config = KConfigParser(configfile, config.options())
|
||||
self.logger.logDebug("*--- Can't find file {}".format(configfile))
|
||||
self.config = config.getdict('ldap',options)
|
||||
self.logger.logDebug("*--- Config list {}".format(self.config))
|
||||
return self.config
|
||||
|
||||
def searchfilter(self, recipient):
|
||||
""" (&(uid=recipient)(kopanoResourceType=publicStore:*)) """
|
||||
""" (&(uid=recipient)(kopanoResourceType=publicFolder:*)) """
|
||||
return ("(&({}={})({}={}:*))"
|
||||
.format(self.config['user_unique_attribute'],
|
||||
recipient,
|
||||
self.config['public_store_attribute'],
|
||||
self.config['public_store_attribute_token']))
|
||||
self.config['public_folder_attribute'],
|
||||
self.config['public_folder_attribute_token']))
|
||||
|
||||
def searchquery(self, recipient):
|
||||
""" Query a LDAP/AD driectory server to lookup recipient using
|
||||
search_base and return public_store_attribute
|
||||
search_base and return public_folder_attribute
|
||||
"""
|
||||
if (self.config['uri'] is None):
|
||||
if not self.config or not self.config['uri']:
|
||||
self.logger.logError(("!--- ldap_uri is not defined."
|
||||
" Please check {}" .format(self.CONFIGFILES[0])))
|
||||
" Please check {}" .format(self.CONFIGFILES)))
|
||||
return None
|
||||
else:
|
||||
l = ldap.initialize(self.config['uri'])
|
||||
try:
|
||||
l.protocol_version = ldap.VERSION3
|
||||
if self.config['starttls'] == 'yes':
|
||||
l.start_tls_s()
|
||||
l.simple_bind_s(self.config['bind_user'] or u'', \
|
||||
self.config['bind_passwd'] or u'')
|
||||
except ldap.SERVER_DOWN as e:
|
||||
|
@ -108,7 +116,7 @@ class MoveToPublic(IMapiDAgentPlugin):
|
|||
return None
|
||||
except ldap.INVALID_CREDENTIALS as e:
|
||||
self.logger.logError(("!--- Invalid LDAP credentials {}"
|
||||
" Please check {}" .format(e, self.CONFIGFILES[0])))
|
||||
" Please check {}" .format(e, self.CONFIGFILES)))
|
||||
l.unbind_s()
|
||||
return None
|
||||
except ldap.LDAPError as e:
|
||||
|
@ -118,19 +126,19 @@ class MoveToPublic(IMapiDAgentPlugin):
|
|||
try:
|
||||
result = l.search_s(self.config['search_base'], \
|
||||
ldap.SCOPE_SUBTREE, self.searchfilter(recipient), \
|
||||
[self.config['public_store_attribute']])
|
||||
[self.config['public_folder_attribute']])
|
||||
except ldap.LDAPError as e:
|
||||
self.logger.logError("!--- LDAPError {}".format(e))
|
||||
l.unbind_s()
|
||||
return result
|
||||
|
||||
def publicfolder(self, recipient):
|
||||
""" Check for ldap_public_store_attribute_token and return folder """
|
||||
""" Check for ldap_public_folder_attribute_token and return folder """
|
||||
destination_folder = []
|
||||
result = self.searchquery(recipient)
|
||||
if result:
|
||||
tokenandfolder = (result[0][1]
|
||||
.get(self.config['public_store_attribute'])[0].decode('utf-8'))
|
||||
.get(self.config['public_folder_attribute'])[0].decode('utf-8'))
|
||||
if tokenandfolder:
|
||||
destination_folder = tokenandfolder.split(':')[1]
|
||||
if destination_folder:
|
||||
|
|
|
@ -25,9 +25,9 @@ class ldapstores():
|
|||
'ldap_bind_passwd': None,
|
||||
'ldap_user_unique_attribute': "uid",
|
||||
'ldap_user_search_filter': "(kopanoAccount=1)",
|
||||
# 'ldap_user_search_filter': "(&(kopanoAccount=1)(kopanoResourceType=publicStore:*))",
|
||||
'ldap_public_store_attribute': "kopanoResourceType",
|
||||
'ldap_public_store_attribute_token': "publicStore"
|
||||
# 'ldap_user_search_filter': "(&(kopanoAccount=1)(kopanoResourceType=publicFolder:*))",
|
||||
'ldap_public_folder_attribute': "kopanoResourceType",
|
||||
'ldap_public_folder_attribute_token': "publicFolder"
|
||||
}
|
||||
|
||||
def __init__(self, configfile = '/etc/kopano/ldap.cfg'):
|
||||
|
@ -58,7 +58,7 @@ class ldapstores():
|
|||
ldap_result_id = l.search(self.config['search_base'], \
|
||||
ldap.SCOPE_SUBTREE, self.config['user_search_filter'], \
|
||||
[self.config['user_unique_attribute'], \
|
||||
self.config['public_store_attribute']])
|
||||
self.config['public_folder_attribute']])
|
||||
results = []
|
||||
while 1:
|
||||
result_type, result_data = l.result(ldap_result_id, 0)
|
||||
|
@ -77,11 +77,11 @@ class ldapstores():
|
|||
public = []
|
||||
for store in stores:
|
||||
recipient = store[1].get(self.config['user_unique_attribute'])
|
||||
tokenandfolder = store[1].get(self.config['ldap_public_store_attribute'])
|
||||
tokenandfolder = store[1].get(self.config['ldap_public_folder_attribute'])
|
||||
if tokenandfolder:
|
||||
token = tokenandfolder.split(':')[0]
|
||||
destination_folder = tokenandfolder.split(':')[1]
|
||||
if (token == self.config['ldap_public_store_attribute_token']);
|
||||
if (token == self.config['ldap_public_folder_attribute_token']);
|
||||
public[recipient] = destination_folder
|
||||
return public
|
||||
|
||||
|
|
Loading…
Reference in New Issue