Commit ceb36f49 authored by Sebastian Kummer's avatar Sebastian Kummer

Merge pull request #645 in ZP/z-push from...

Merge pull request #645 in ZP/z-push from bugfix/ZP-1329-z-push-admin-doesn-t-work-on-impersonated-accounts to develop

* commit '7da39ad1':
  ZP-1329 Fixed typos.
  ZP-1329 Removed not necessary else cases.
  ZP-1329 Log impersonated user also in syslog.
  ZP-1329 Send ReplyBack notification email to the authenticated user, as he lacks permissions.
  ZP-1329 Revert IBackend->Logon() change.
  ZP-1329 Revert IBackend->Logon() modifications and remove the $impersonatedUsername to keep backward compatibility. This needs to be redone in ZP-1351.
  ZP-1329 Refactored impersonation feature to a global level.
parents d21a3fe7 7da39ad1
...@@ -71,7 +71,6 @@ class BackendKopano implements IBackend, ISearchProvider { ...@@ -71,7 +71,6 @@ class BackendKopano implements IBackend, ISearchProvider {
const FREEBUSYENUMBLOCKS = 50; const FREEBUSYENUMBLOCKS = 50;
const MAXFREEBUSYSLOTS = 32767; // max length of 32k for the MergedFreeBusy element is allowed const MAXFREEBUSYSLOTS = 32767; // max length of 32k for the MergedFreeBusy element is allowed
const HALFHOURSECONDS = 1800; const HALFHOURSECONDS = 1800;
const IMPERSONATE_DELIM = '+share+';
/** /**
* Constructor of the Kopano Backend * Constructor of the Kopano Backend
...@@ -143,16 +142,17 @@ class BackendKopano implements IBackend, ISearchProvider { ...@@ -143,16 +142,17 @@ class BackendKopano implements IBackend, ISearchProvider {
public function Logon($user, $domain, $pass) { public function Logon($user, $domain, $pass) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): Trying to authenticate user '%s'..", $user)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): Trying to authenticate user '%s'..", $user));
$this->mainUser = strtolower($user);
// TODO the impersonated user should be passed directly to IBackend->Logon() - ZP-1351
$this->impersonateUser = Request::GetImpersonatedUser();
// check if we are impersonating someone // check if we are impersonating someone
// $defaultUser will be used for $this->defaultStore // $defaultUser will be used for $this->defaultStore
if (defined('KOE_CAPABILITY_IMPERSONATE') && KOE_CAPABILITY_IMPERSONATE && stripos($user, self::IMPERSONATE_DELIM) !== false) { if ($this->impersonateUser !== 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)); ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->Logon(): Impersonation active - authenticating: '%s' - impersonating '%s'", $this->mainUser, $this->impersonateUser));
$defaultUser = $this->impersonateUser; $defaultUser = $this->impersonateUser;
} }
else { else {
$this->mainUser = strtolower($user);
$this->impersonateUser = false;
$defaultUser = $this->mainUser; $defaultUser = $this->mainUser;
} }
......
...@@ -310,7 +310,7 @@ class MAPIProvider { ...@@ -310,7 +310,7 @@ class MAPIProvider {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->getAppointment: adding ourself as an attendee for iOS6 workaround")); ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->getAppointment: adding ourself as an attendee for iOS6 workaround"));
$attendee = new SyncAttendee(); $attendee = new SyncAttendee();
$meinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetAuthUser()); $meinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetUser());
if (is_array($meinfo)) { if (is_array($meinfo)) {
$attendee->email = w2u($meinfo["emailaddress"]); $attendee->email = w2u($meinfo["emailaddress"]);
...@@ -327,7 +327,7 @@ class MAPIProvider { ...@@ -327,7 +327,7 @@ class MAPIProvider {
// the user is the owner or it will not work properly with android devices // the user is the owner or it will not work properly with android devices
// @see https://jira.z-hub.io/browse/ZP-1020 // @see https://jira.z-hub.io/browse/ZP-1020
if(isset($messageprops[$appointmentprops["meetingstatus"]]) && $messageprops[$appointmentprops["meetingstatus"]] == olNonMeeting && empty($message->attendees)) { if(isset($messageprops[$appointmentprops["meetingstatus"]]) && $messageprops[$appointmentprops["meetingstatus"]] == olNonMeeting && empty($message->attendees)) {
$meinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetAuthUser()); $meinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetUser());
if (is_array($meinfo)) { if (is_array($meinfo)) {
$message->organizeremail = w2u($meinfo["emailaddress"]); $message->organizeremail = w2u($meinfo["emailaddress"]);
...@@ -1467,8 +1467,8 @@ class MAPIProvider { ...@@ -1467,8 +1467,8 @@ class MAPIProvider {
$props[$appointmentprops["representingentryid"]] = $storeProps[PR_MAILBOX_OWNER_ENTRYID]; $props[$appointmentprops["representingentryid"]] = $storeProps[PR_MAILBOX_OWNER_ENTRYID];
$displayname = $this->getFullnameFromEntryID($storeProps[PR_MAILBOX_OWNER_ENTRYID]); $displayname = $this->getFullnameFromEntryID($storeProps[PR_MAILBOX_OWNER_ENTRYID]);
$props[$appointmentprops["representingname"]] = ($displayname !== false) ? $displayname : Request::GetAuthUser(); $props[$appointmentprops["representingname"]] = ($displayname !== false) ? $displayname : Request::GetUser();
$props[$appointmentprops["sentrepresentingemail"]] = Request::GetAuthUser(); $props[$appointmentprops["sentrepresentingemail"]] = Request::GetUser();
$props[$appointmentprops["sentrepresentingaddt"]] = "ZARAFA"; $props[$appointmentprops["sentrepresentingaddt"]] = "ZARAFA";
$props[$appointmentprops["sentrepresentinsrchk"]] = $props[$appointmentprops["sentrepresentingaddt"]].":".$props[$appointmentprops["sentrepresentingemail"]]; $props[$appointmentprops["sentrepresentinsrchk"]] = $props[$appointmentprops["sentrepresentingaddt"]].":".$props[$appointmentprops["sentrepresentingemail"]];
...@@ -1742,7 +1742,7 @@ class MAPIProvider { ...@@ -1742,7 +1742,7 @@ class MAPIProvider {
$p = array( $taskprops["owner"]); $p = array( $taskprops["owner"]);
$owner = $this->getProps($mapimessage, $p); $owner = $this->getProps($mapimessage, $p);
if (!isset($owner[$taskprops["owner"]])) { if (!isset($owner[$taskprops["owner"]])) {
$userinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetAuthUser()); $userinfo = mapi_zarafa_getuser_by_name($this->store, Request::GetUser());
if(mapi_last_hresult() == NOERROR && isset($userinfo["fullname"])) { if(mapi_last_hresult() == NOERROR && isset($userinfo["fullname"])) {
$props[$taskprops["owner"]] = $userinfo["fullname"]; $props[$taskprops["owner"]] = $userinfo["fullname"];
} }
......
...@@ -509,7 +509,7 @@ class ReplyBackImExporter implements IImportChanges, IExportChanges { ...@@ -509,7 +509,7 @@ class ReplyBackImExporter implements IImportChanges, IExportChanges {
* @return void * @return void
*/ */
private function sendNotificationEmail($message, $oldmessage) { private function sendNotificationEmail($message, $oldmessage) {
// get email address and full name of the user // get email address and full name of the user that performed the operation (auth user in all cases)
$userinfo = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser()); $userinfo = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser());
// get the name of the folder // get the name of the folder
......
...@@ -97,7 +97,7 @@ abstract class InterProcessData { ...@@ -97,7 +97,7 @@ abstract class InterProcessData {
if (!isset(self::$devid)) { if (!isset(self::$devid)) {
self::$devid = Request::GetDeviceID(); self::$devid = Request::GetDeviceID();
self::$pid = @getmypid(); self::$pid = @getmypid();
self::$user = Request::GetAuthUser(); self::$user = Request::GetAuthUserString(); // we want to see everything here
self::$start = time(); self::$start = time();
} }
return true; return true;
......
...@@ -145,8 +145,13 @@ class ZLog { ...@@ -145,8 +145,13 @@ class ZLog {
throw new \Exception($errmsg); throw new \Exception($errmsg);
} }
list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser())); // if there is an impersonated user it's used instead of the GET user
$user = '['.$user.']'; if (Request::GetImpersonatedUser()) {
$user = Request::GetImpersonatedUser();
}
else {
list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser()));
}
self::$logger = new $logger(); self::$logger = new $logger();
self::$logger->SetUser($user); self::$logger->SetUser($user);
......
...@@ -182,16 +182,16 @@ abstract class Backend implements IBackend { ...@@ -182,16 +182,16 @@ abstract class Backend implements IBackend {
if (Request::GetProtocolVersion() >= 14.1) { if (Request::GetProtocolVersion() >= 14.1) {
$account = new SyncAccount(); $account = new SyncAccount();
$emailaddresses = new SyncEmailAddresses(); $emailaddresses = new SyncEmailAddresses();
$emailaddresses->smtpaddress[] = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress']; $emailaddresses->smtpaddress[] = ZPush::GetBackend()->GetUserDetails(Request::GetUser())['emailaddress'];
$emailaddresses->primarysmtpaddress = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress']; $emailaddresses->primarysmtpaddress = ZPush::GetBackend()->GetUserDetails(Request::GetUser())['emailaddress'];
$account->emailaddresses = $emailaddresses; $account->emailaddresses = $emailaddresses;
$userinformation->accounts[] = $account; $userinformation->accounts[] = $account;
} }
else { else {
$userinformation->emailaddresses = array(ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress']); $userinformation->emailaddresses = array(ZPush::GetBackend()->GetUserDetails(Request::GetUser())['emailaddress']);
} }
$settings->emailaddresses = array(ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress']); $settings->emailaddresses = array(ZPush::GetBackend()->GetUserDetails(Request::GetUser())['emailaddress']);
} }
if ($settings instanceof SyncRightsManagementTemplates) { if ($settings instanceof SyncRightsManagementTemplates) {
...@@ -233,7 +233,7 @@ abstract class Backend implements IBackend { ...@@ -233,7 +233,7 @@ abstract class Backend implements IBackend {
* @return Array * @return Array
*/ */
public function GetCurrentUsername() { public function GetCurrentUsername() {
return $this->GetUserDetails(Request::GetAuthUser()); return $this->GetUserDetails(Request::GetUser());
} }
/** /**
......
...@@ -50,6 +50,7 @@ class FileLog extends Log { ...@@ -50,6 +50,7 @@ class FileLog extends Log {
else { else {
$this->setLogToUserFile( $this->setLogToUserFile(
preg_replace('/[^a-z0-9]/', '_', strtolower($this->GetAuthUser())) .'-'. preg_replace('/[^a-z0-9]/', '_', strtolower($this->GetAuthUser())) .'-'.
(($this->GetAuthUser() != $this->GetUser()) ? preg_replace('/[^a-z0-9]/', '_', strtolower($this->GetUser())) .'-' : '') .
preg_replace('/[^a-z0-9]/', '_', strtolower($this->GetDevid())) . preg_replace('/[^a-z0-9]/', '_', strtolower($this->GetDevid())) .
'.log' '.log'
); );
...@@ -84,7 +85,13 @@ class FileLog extends Log { ...@@ -84,7 +85,13 @@ class FileLog extends Log {
$log = Utils::GetFormattedTime() .' ['. str_pad($this->GetPid(),5," ",STR_PAD_LEFT) .'] '. $this->GetLogLevelString($loglevel, $loglevel >= LOGLEVEL_INFO); $log = Utils::GetFormattedTime() .' ['. str_pad($this->GetPid(),5," ",STR_PAD_LEFT) .'] '. $this->GetLogLevelString($loglevel, $loglevel >= LOGLEVEL_INFO);
if ($includeUserDevice) { if ($includeUserDevice) {
$log .= ' '. $this->GetUser(); // when the users differ, we need to log both
if ($this->GetUser() != $this->GetAuthUser()) {
$log .= ' ['. $this->GetAuthUser() . Request::IMPERSONATE_DELIM . $this->GetUser() .']';
}
else {
$log .= ' ['. $this->GetUser() .']';
}
} }
if ($includeUserDevice && (LOGLEVEL >= LOGLEVEL_DEVICEID || (LOGUSERLEVEL >= LOGLEVEL_DEVICEID && $this->IsAuthUserInSpecialLogUsers()))) { if ($includeUserDevice && (LOGLEVEL >= LOGLEVEL_DEVICEID || (LOGUSERLEVEL >= LOGLEVEL_DEVICEID && $this->IsAuthUserInSpecialLogUsers()))) {
$log .= ' ['. $this->GetDevid() .']'; $log .= ' ['. $this->GetDevid() .']';
......
...@@ -166,7 +166,13 @@ class Syslog extends Log { ...@@ -166,7 +166,13 @@ class Syslog extends Log {
*/ */
public function BuildLogString($loglevel, $message, $includeUserDevice = true) { public function BuildLogString($loglevel, $message, $includeUserDevice = true) {
$log = $this->GetLogLevelString($loglevel); // Never pad syslog log because syslog log are usually read with a software. $log = $this->GetLogLevelString($loglevel); // Never pad syslog log because syslog log are usually read with a software.
$log .= $this->GetUser(); // when the users differ, we need to log both
if ($this->GetUser() != $this->GetAuthUser()) {
$log .= ' ['. $this->GetAuthUser() . Request::IMPERSONATE_DELIM . $this->GetUser() .']';
}
else {
$log .= ' ['. $this->GetUser() .']';
}
if ($loglevel >= LOGLEVEL_DEVICEID) { if ($loglevel >= LOGLEVEL_DEVICEID) {
$log .= '['. $this->GetDevid() .']'; $log .= '['. $this->GetDevid() .']';
} }
......
...@@ -198,7 +198,7 @@ class FolderSync extends RequestProcessor { ...@@ -198,7 +198,7 @@ class FolderSync extends RequestProcessor {
// say that we are done with partial synching // say that we are done with partial synching
self::$deviceManager->SetFolderSyncComplete(true); self::$deviceManager->SetFolderSyncComplete(true);
// reset the loop data to prevent any loop detection to kick in now // reset the loop data to prevent any loop detection to kick in now
self::$deviceManager->ClearLoopDetectionData(Request::GetAuthUser(), Request::GetDeviceID()); self::$deviceManager->ClearLoopDetectionData(Request::GetAuthUserString(), Request::GetDeviceID());
ZLog::Write(LOGLEVEL_INFO, "Request->HandleFolderSync(): Chunked exporting of folders completed successfully"); ZLog::Write(LOGLEVEL_INFO, "Request->HandleFolderSync(): Chunked exporting of folders completed successfully");
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
class Request { class Request {
const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when synching const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when synching
const UNKNOWN = "unknown"; const UNKNOWN = "unknown";
const IMPERSONATE_DELIM = '#';
/** /**
* self::filterEvilInput() options * self::filterEvilInput() options
...@@ -65,9 +66,11 @@ class Request { ...@@ -65,9 +66,11 @@ class Request {
static private $getUser; static private $getUser;
static private $devid; static private $devid;
static private $devtype; static private $devtype;
static private $authUserString;
static private $authUser; static private $authUser;
static private $authDomain; static private $authDomain;
static private $authPassword; static private $authPassword;
static private $impersonatedUser;
static private $asProtocolVersion; static private $asProtocolVersion;
static private $policykey; static private $policykey;
static private $useragent; static private $useragent;
...@@ -179,9 +182,17 @@ class Request { ...@@ -179,9 +182,17 @@ class Request {
// authUser & authPassword are unfiltered! // authUser & authPassword are unfiltered!
// split username & domain if received as one // split username & domain if received as one
if (isset($_SERVER['PHP_AUTH_USER'])) { if (isset($_SERVER['PHP_AUTH_USER'])) {
list(self::$authUser, self::$authDomain) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']); list(self::$authUserString, self::$authDomain) = Utils::SplitDomainUser($_SERVER['PHP_AUTH_USER']);
self::$authPassword = (isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW'] : ""; self::$authPassword = (isset($_SERVER['PHP_AUTH_PW']))?$_SERVER['PHP_AUTH_PW'] : "";
} }
// process impersonation
self::$authUser = self::$authUserString; // auth will fail when impersonating & KOE_CAPABILITY_IMPERSONATE is disabled
if (defined('KOE_CAPABILITY_IMPERSONATE') && KOE_CAPABILITY_IMPERSONATE && stripos(self::$authUserString, self::IMPERSONATE_DELIM) !== false) {
list(self::$authUser, self::$impersonatedUser) = explode(self::IMPERSONATE_DELIM, strtolower(self::$authUserString));
}
if(defined('USE_FULLEMAIL_FOR_LOGIN') && ! USE_FULLEMAIL_FOR_LOGIN) { if(defined('USE_FULLEMAIL_FOR_LOGIN') && ! USE_FULLEMAIL_FOR_LOGIN) {
self::$authUser = Utils::GetLocalPartFromEmail(self::$authUser); self::$authUser = Utils::GetLocalPartFromEmail(self::$authUser);
} }
...@@ -391,16 +402,57 @@ class Request { ...@@ -391,16 +402,57 @@ class Request {
} }
/** /**
* Returns the authenticated user * Returns user that is synchronizing data.
* If impersonation is active it returns the impersonated user,
* else the auth user.
*
* @access public
* @return string/boolean false if not available
*/
static public function GetUser() {
if (self::GetImpersonatedUser()) {
return self::GetImpersonatedUser();
}
return self::GetAuthUser();
}
/**
* Returns the AuthUser string send by the client.
*
* @access public
* @return string/boolean false if not available
*/
static public function GetAuthUserString() {
if (isset(self::$authUserString)) {
return self::$authUserString;
}
return false;
}
/**
* Returns the impersonated user. If not available, returns false.
*
* @access public
* @return string/boolean false if not available
*/
static public function GetImpersonatedUser() {
if (isset(self::$impersonatedUser)) {
return self::$impersonatedUser;
}
return false;
}
/**
* Returns the authenticated user.
* *
* @access public * @access public
* @return string/boolean false if not available * @return string/boolean false if not available
*/ */
static public function GetAuthUser() { static public function GetAuthUser() {
if (isset(self::$authUser)) if (isset(self::$authUser)) {
return self::$authUser; return self::$authUser;
else }
return false; return false;
} }
/** /**
......
...@@ -60,6 +60,10 @@ abstract class RequestProcessor { ...@@ -60,6 +60,10 @@ abstract class RequestProcessor {
if(defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser())) if(defined("CERTIFICATE_OWNER_PARAMETER") && isset($_SERVER[CERTIFICATE_OWNER_PARAMETER]) && strtolower($_SERVER[CERTIFICATE_OWNER_PARAMETER]) != strtolower(Request::GetAuthUser()))
throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER])); throw new AuthenticationRequiredException(sprintf("Access denied. Access is allowed only for the certificate owner '%s'", $_SERVER[CERTIFICATE_OWNER_PARAMETER]));
if (Request::GetImpersonatedUser() && Request::GetAuthUser() != Request::GetImpersonatedUser()) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("RequestProcessor->Authenticate(): Impersonation active - authenticating: '%s' - impersonating '%s'", Request::GetAuthUser(), Request::GetImpersonatedUser()));
}
$backend = ZPush::GetBackend(); $backend = ZPush::GetBackend();
if($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false) if($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false)
throw new AuthenticationRequiredException("Access denied. Username or password incorrect"); throw new AuthenticationRequiredException("Access denied. Username or password incorrect");
......
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