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 {
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
......@@ -143,16 +142,17 @@ 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);
// TODO the impersonated user should be passed directly to IBackend->Logon() - ZP-1351
$this->impersonateUser = Request::GetImpersonatedUser();
// check if we are impersonating someone
// $defaultUser will be used for $this->defaultStore
if (defined('KOE_CAPABILITY_IMPERSONATE') && KOE_CAPABILITY_IMPERSONATE && stripos($user, self::IMPERSONATE_DELIM) !== false) {
list($this->mainUser, $this->impersonateUser) = explode(self::IMPERSONATE_DELIM, strtolower($user));
if ($this->impersonateUser !== false) {
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;
}
......
......@@ -310,7 +310,7 @@ class MAPIProvider {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->getAppointment: adding ourself as an attendee for iOS6 workaround"));
$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)) {
$attendee->email = w2u($meinfo["emailaddress"]);
......@@ -327,7 +327,7 @@ class MAPIProvider {
// the user is the owner or it will not work properly with android devices
// @see https://jira.z-hub.io/browse/ZP-1020
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)) {
$message->organizeremail = w2u($meinfo["emailaddress"]);
......@@ -1467,8 +1467,8 @@ class MAPIProvider {
$props[$appointmentprops["representingentryid"]] = $storeProps[PR_MAILBOX_OWNER_ENTRYID];
$displayname = $this->getFullnameFromEntryID($storeProps[PR_MAILBOX_OWNER_ENTRYID]);
$props[$appointmentprops["representingname"]] = ($displayname !== false) ? $displayname : Request::GetAuthUser();
$props[$appointmentprops["sentrepresentingemail"]] = Request::GetAuthUser();
$props[$appointmentprops["representingname"]] = ($displayname !== false) ? $displayname : Request::GetUser();
$props[$appointmentprops["sentrepresentingemail"]] = Request::GetUser();
$props[$appointmentprops["sentrepresentingaddt"]] = "ZARAFA";
$props[$appointmentprops["sentrepresentinsrchk"]] = $props[$appointmentprops["sentrepresentingaddt"]].":".$props[$appointmentprops["sentrepresentingemail"]];
......@@ -1742,7 +1742,7 @@ class MAPIProvider {
$p = array( $taskprops["owner"]);
$owner = $this->getProps($mapimessage, $p);
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"])) {
$props[$taskprops["owner"]] = $userinfo["fullname"];
}
......
......@@ -509,7 +509,7 @@ class ReplyBackImExporter implements IImportChanges, IExportChanges {
* @return void
*/
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());
// get the name of the folder
......
......@@ -97,7 +97,7 @@ abstract class InterProcessData {
if (!isset(self::$devid)) {
self::$devid = Request::GetDeviceID();
self::$pid = @getmypid();
self::$user = Request::GetAuthUser();
self::$user = Request::GetAuthUserString(); // we want to see everything here
self::$start = time();
}
return true;
......
......@@ -145,8 +145,13 @@ class ZLog {
throw new \Exception($errmsg);
}
list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser()));
$user = '['.$user.']';
// if there is an impersonated user it's used instead of the GET user
if (Request::GetImpersonatedUser()) {
$user = Request::GetImpersonatedUser();
}
else {
list($user) = Utils::SplitDomainUser(strtolower(Request::GetGETUser()));
}
self::$logger = new $logger();
self::$logger->SetUser($user);
......
......@@ -182,16 +182,16 @@ abstract class Backend implements IBackend {
if (Request::GetProtocolVersion() >= 14.1) {
$account = new SyncAccount();
$emailaddresses = new SyncEmailAddresses();
$emailaddresses->smtpaddress[] = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress'];
$emailaddresses->primarysmtpaddress = ZPush::GetBackend()->GetUserDetails(Request::GetAuthUser())['emailaddress'];
$emailaddresses->smtpaddress[] = ZPush::GetBackend()->GetUserDetails(Request::GetUser())['emailaddress'];
$emailaddresses->primarysmtpaddress = ZPush::GetBackend()->GetUserDetails(Request::GetUser())['emailaddress'];
$account->emailaddresses = $emailaddresses;
$userinformation->accounts[] = $account;
}
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) {
......@@ -233,7 +233,7 @@ abstract class Backend implements IBackend {
* @return Array
*/
public function GetCurrentUsername() {
return $this->GetUserDetails(Request::GetAuthUser());
return $this->GetUserDetails(Request::GetUser());
}
/**
......
......@@ -50,6 +50,7 @@ class FileLog extends Log {
else {
$this->setLogToUserFile(
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())) .
'.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);
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()))) {
$log .= ' ['. $this->GetDevid() .']';
......
......@@ -166,7 +166,13 @@ class Syslog extends Log {
*/
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->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) {
$log .= '['. $this->GetDevid() .']';
}
......
......@@ -198,7 +198,7 @@ class FolderSync extends RequestProcessor {
// say that we are done with partial synching
self::$deviceManager->SetFolderSyncComplete(true);
// 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");
}
......
......@@ -27,6 +27,7 @@
class Request {
const MAXMEMORYUSAGE = 0.9; // use max. 90% of allowed memory when synching
const UNKNOWN = "unknown";
const IMPERSONATE_DELIM = '#';
/**
* self::filterEvilInput() options
......@@ -65,9 +66,11 @@ class Request {
static private $getUser;
static private $devid;
static private $devtype;
static private $authUserString;
static private $authUser;
static private $authDomain;
static private $authPassword;
static private $impersonatedUser;
static private $asProtocolVersion;
static private $policykey;
static private $useragent;
......@@ -179,9 +182,17 @@ class Request {
// authUser & authPassword are unfiltered!
// split username & domain if received as one
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'] : "";
}
// 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) {
self::$authUser = Utils::GetLocalPartFromEmail(self::$authUser);
}
......@@ -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
* @return string/boolean false if not available
*/
static public function GetAuthUser() {
if (isset(self::$authUser))
if (isset(self::$authUser)) {
return self::$authUser;
else
return false;
}
return false;
}
/**
......
......@@ -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()))
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();
if($backend->Logon(Request::GetAuthUser(), Request::GetAuthDomain(), Request::GetAuthPassword()) == false)
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