Commit d6dd4515 authored by Sebastian Kummer's avatar Sebastian Kummer

ZP-1271 Impersonating support for the Kopano backend. Send-As with OL

working correctly.

Released under the Affero GNU General Public License (AGPL) version 3.
parent 772b10f8
......@@ -61,6 +61,7 @@ class BackendKopano implements IBackend, ISearchProvider {
private $wastebasket;
private $addressbook;
private $folderStatCache;
private $impersonateUser;
// KC config parameter for PR_EC_ENABLED_FEATURES / PR_EC_DISABLED_FEATURES
const MOBILE_ENABLED = 'mobile';
......@@ -70,6 +71,7 @@ class BackendKopano implements IBackend, ISearchProvider {
const FREEBUSYENUMBLOCKS = 50;
const MAXFREEBUSYSLOTS = 32767; // max length of 32k for the MergedFreeBusy element is allowed
const HALFHOURSECONDS = 1800;
const IMPERSONATE_DELIM = '+share+';
/**
* Constructor of the Kopano Backend
......@@ -90,6 +92,7 @@ class BackendKopano implements IBackend, ISearchProvider {
$this->wastebasket = false;
$this->session = false;
$this->folderStatCache = array();
$this->impersonateUser = false;
ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendKopano using PHP-MAPI version: %s - PHP version: %s", phpversion("mapi"), phpversion()));
KopanoChangesWrapper::SetBackend($this);
......@@ -139,7 +142,19 @@ class BackendKopano implements IBackend, ISearchProvider {
*/
public function Logon($user, $domain, $pass) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): Trying to authenticate user '%s'..", $user));
$this->mainUser = strtolower($user);
// check if we are impersonating someone
// $defaultUser will be used for $this->defaultStore
if (stripos($user, self::IMPERSONATE_DELIM) !== false) {
list($this->mainUser, $this->impersonateUser) = explode(self::IMPERSONATE_DELIM, strtolower($user));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): Impersonation active - authenticating: '%s' - impersonating '%s'", $this->mainUser, $this->impersonateUser));
$defaultUser = $this->impersonateUser;
}
else {
$this->mainUser = strtolower($user);
$this->impersonateUser = false;
$defaultUser = $this->mainUser;
}
try {
// check if notifications are available in php-mapi
......@@ -148,16 +163,16 @@ class BackendKopano implements IBackend, ISearchProvider {
if (Utils::CheckMapiExtVersion('7.2.0')) {
$zpush_version = 'Z-Push_' . @constant('ZPUSH_VERSION');
$user_agent = (Request::GetDeviceID()) ? ZPush::GetDeviceManager()->GetUserAgent() : "unknown";
$this->session = @mapi_logon_zarafa($user, $pass, MAPI_SERVER, null, null, 0, $zpush_version, $user_agent);
$this->session = @mapi_logon_zarafa($this->mainUser, $pass, MAPI_SERVER, null, null, 0, $zpush_version, $user_agent);
}
else {
$this->session = @mapi_logon_zarafa($user, $pass, MAPI_SERVER, null, null, 0);
$this->session = @mapi_logon_zarafa($this->mainUser, $pass, MAPI_SERVER, null, null, 0);
}
$this->notifications = true;
}
// old fashioned session
else {
$this->session = @mapi_logon_zarafa($user, $pass, MAPI_SERVER);
$this->session = @mapi_logon_zarafa($this->mainUser, $pass, MAPI_SERVER);
$this->notifications = false;
}
......@@ -172,7 +187,7 @@ class BackendKopano implements IBackend, ISearchProvider {
}
if(!$this->session) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): logon failed for user '%s'", $user));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): logon failed for user '%s'", $this->mainUser));
$this->defaultstore = false;
return false;
}
......@@ -180,16 +195,22 @@ class BackendKopano implements IBackend, ISearchProvider {
// Get/open default store
$this->defaultstore = $this->openMessageStore($this->mainUser);
// To impersonate, we overwrite the defaultstore. We still need to open it before we can do that.
if ($this->impersonateUser) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): Impersonating user '%s'", $defaultUser));
$this->defaultstore = $this->openMessageStore($defaultUser);
}
if (mapi_last_hresult() == MAPI_E_FAILONEPROVIDER)
throw new ServiceUnavailableException("Error connecting to KC (open store)");
if($this->defaultstore === false)
throw new AuthenticationRequiredException(sprintf("KopanoBackend->Logon(): User '%s' has no default store", $user));
throw new AuthenticationRequiredException(sprintf("KopanoBackend->Logon(): User '%s' has no default store", $defaultUser));
$this->store = $this->defaultstore;
$this->storeName = $this->mainUser;
$this->storeName = $defaultUser;
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): User '%s' is authenticated",$user));
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): User '%s' is authenticated%s", $this->mainUser, ($this->impersonateUser ? " impersonating '".$this->impersonateUser."'":'')));
$this->isZPushEnabled();
......@@ -224,13 +245,19 @@ class BackendKopano implements IBackend, ISearchProvider {
if (!isset($this->mainUser))
return false;
$mainUser = $this->mainUser;
// when impersonating we need to check against the impersonated user
if ($this->impersonateUser) {
$mainUser = $this->impersonateUser;
}
if ($user === false)
$user = $this->mainUser;
$user = $mainUser;
// This is a special case. A user will get his entire folder structure by the foldersync by default.
// The ACL check is executed when an additional folder is going to be sent to the mobile.
// Configured that way the user could receive the same folderid twice, with two different names.
if ($this->mainUser == $user && $checkACLonly && $folderid) {
if ($mainUser == $user && $checkACLonly && $folderid) {
ZLog::Write(LOGLEVEL_DEBUG, "KopanoBackend->Setup(): Checking ACLs for folder of the users defaultstore. Fail is forced to avoid folder duplications on mobile.");
return false;
}
......@@ -244,8 +271,8 @@ class BackendKopano implements IBackend, ISearchProvider {
if ($checkACLonly == true) {
// check for admin rights
if (!$folderid) {
if ($user != $this->mainUser) {
$zarafauserinfo = @mapi_zarafa_getuser_by_name($this->defaultstore, $this->mainUser);
if ($user != $mainUser) {
$zarafauserinfo = @mapi_zarafa_getuser_by_name($this->defaultstore, $mainUser);
$admin = (isset($zarafauserinfo['admin']) && $zarafauserinfo['admin'])?true:false;
}
// the user has always full access to his own store
......@@ -499,6 +526,13 @@ class BackendKopano implements IBackend, ISearchProvider {
}
}
// When impersonating we are also "sendingAsSomeone". We also need to switch to the defaultstore
// to put the message in our own Outbox. Kopano will save a copy in the impersonted Sent Items folder.
if ($this->impersonateUser) {
$this->defaultstore = $this->openMessageStore($this->mainUser);
$sendingAsSomeone = true;
}
$sendMailProps = MAPIMapping::GetSendMailProperties();
$sendMailProps = getPropIdsFromStrings($this->defaultstore, $sendMailProps);
......@@ -563,6 +597,7 @@ class BackendKopano implements IBackend, ISearchProvider {
mapi_deleteprops($mapimessage,
array( $sendMailProps["sentrepresentingname"], $sendMailProps["sentrepresentingemail"], $sendMailProps["representingentryid"],
$sendMailProps["sentrepresentingaddt"], $sendMailProps["sentrepresentinsrchk"]));
ZLog::Write(LOGLEVEL_DEBUG, "KopanoBackend->SendMail(): removing PR_SENT_REPRESENTING_* properties");
}
// Processing of KOE X-Push-Receipts header - delivery notification: ZP-1204
......@@ -1480,6 +1515,9 @@ class BackendKopano implements IBackend, ISearchProvider {
if ($user === false) {
$user = $this->mainUser;
}
if ($this->impersonateUser) {
$user = $this->impersonateUser;
}
// if there is a ReplyBackImExporter, the exporter needs to run!
$wrapper = KopanoChangesWrapper::GetWrapper($user, false, null, $folderid, null);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment