user.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <?php
  2. /**
  3. * ownCloud – LDAP User
  4. *
  5. * @author Arthur Schiwon
  6. * @copyright 2014 Arthur Schiwon blizzz@owncloud.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace OCA\user_ldap\lib\user;
  23. use OCA\user_ldap\lib\user\IUserTools;
  24. use OCA\user_ldap\lib\Connection;
  25. use OCA\user_ldap\lib\FilesystemHelper;
  26. use OCA\user_ldap\lib\LogWrapper;
  27. /**
  28. * User
  29. *
  30. * represents an LDAP user, gets and holds user-specific information from LDAP
  31. */
  32. class User {
  33. /**
  34. * @var IUserTools
  35. */
  36. protected $access;
  37. /**
  38. * @var Connection
  39. */
  40. protected $connection;
  41. /**
  42. * @var \OCP\IConfig
  43. */
  44. protected $config;
  45. /**
  46. * @var FilesystemHelper
  47. */
  48. protected $fs;
  49. /**
  50. * @var \OCP\Image
  51. */
  52. protected $image;
  53. /**
  54. * @var LogWrapper
  55. */
  56. protected $log;
  57. /**
  58. * @var \OCP\IAvatarManager
  59. */
  60. protected $avatarManager;
  61. /**
  62. * @var string
  63. */
  64. protected $dn;
  65. /**
  66. * @var string
  67. */
  68. protected $uid;
  69. /**
  70. * @var string[]
  71. */
  72. protected $refreshedFeatures = array();
  73. /**
  74. * @var string
  75. */
  76. protected $avatarImage;
  77. /**
  78. * DB config keys for user preferences
  79. */
  80. const USER_PREFKEY_FIRSTLOGIN = 'firstLoginAccomplished';
  81. const USER_PREFKEY_LASTREFRESH = 'lastFeatureRefresh';
  82. /**
  83. * @brief constructor, make sure the subclasses call this one!
  84. * @param string the internal username
  85. * @param string the LDAP DN
  86. * @param IUserTools $access an instance that implements IUserTools for
  87. * LDAP interaction
  88. * @param \OCP\IConfig
  89. * @param FilesystemHelper
  90. * @param \OCP\Image any empty instance
  91. * @param LogWrapper
  92. * @param \OCP\IAvatarManager
  93. */
  94. public function __construct($username, $dn, IUserTools $access,
  95. \OCP\IConfig $config, FilesystemHelper $fs, \OCP\Image $image,
  96. LogWrapper $log, \OCP\IAvatarManager $avatarManager) {
  97. $this->access = $access;
  98. $this->connection = $access->getConnection();
  99. $this->config = $config;
  100. $this->fs = $fs;
  101. $this->dn = $dn;
  102. $this->uid = $username;
  103. $this->image = $image;
  104. $this->log = $log;
  105. $this->avatarManager = $avatarManager;
  106. }
  107. /**
  108. * @brief updates properties like email, quota or avatar provided by LDAP
  109. * @return null
  110. */
  111. public function update() {
  112. if(is_null($this->dn)) {
  113. return null;
  114. }
  115. $hasLoggedIn = $this->config->getUserValue($this->uid, 'user_ldap',
  116. self::USER_PREFKEY_FIRSTLOGIN, 0);
  117. if($this->needsRefresh()) {
  118. $this->updateEmail();
  119. $this->updateQuota();
  120. if($hasLoggedIn !== 0) {
  121. //we do not need to try it, when the user has not been logged in
  122. //before, because the file system will not be ready.
  123. $this->updateAvatar();
  124. //in order to get an avatar as soon as possible, mark the user
  125. //as refreshed only when updating the avatar did happen
  126. $this->markRefreshTime();
  127. }
  128. }
  129. }
  130. /**
  131. * @brief returns the LDAP DN of the user
  132. * @return string
  133. */
  134. public function getDN() {
  135. return $this->dn;
  136. }
  137. /**
  138. * @brief returns the ownCloud internal username of the user
  139. * @return string
  140. */
  141. public function getUsername() {
  142. return $this->uid;
  143. }
  144. /**
  145. * @brief reads the image from LDAP that shall be used as Avatar
  146. * @return string data (provided by LDAP) | false
  147. */
  148. public function getAvatarImage() {
  149. if(!is_null($this->avatarImage)) {
  150. return $this->avatarImage;
  151. }
  152. $this->avatarImage = false;
  153. $attributes = array('jpegPhoto', 'thumbnailPhoto');
  154. foreach($attributes as $attribute) {
  155. $result = $this->access->readAttribute($this->dn, $attribute);
  156. if($result !== false && is_array($result) && isset($result[0])) {
  157. $this->avatarImage = $result[0];
  158. break;
  159. }
  160. }
  161. return $this->avatarImage;
  162. }
  163. /**
  164. * @brief marks the user as having logged in at least once
  165. * @return null
  166. */
  167. public function markLogin() {
  168. $this->config->setUserValue(
  169. $this->uid, 'user_ldap', self::USER_PREFKEY_FIRSTLOGIN, 1);
  170. }
  171. /**
  172. * @brief marks the time when user features like email have been updated
  173. * @return null
  174. */
  175. private function markRefreshTime() {
  176. $this->config->setUserValue(
  177. $this->uid, 'user_ldap', self::USER_PREFKEY_LASTREFRESH, time());
  178. }
  179. /**
  180. * @brief checks whether user features needs to be updated again by
  181. * comparing the difference of time of the last refresh to now with the
  182. * desired interval
  183. * @return bool
  184. */
  185. private function needsRefresh() {
  186. $lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
  187. self::USER_PREFKEY_LASTREFRESH, 0);
  188. //TODO make interval configurable
  189. if((time() - intval($lastChecked)) < 86400 ) {
  190. return false;
  191. }
  192. return true;
  193. }
  194. /**
  195. * Stores a key-value pair in relation to this user
  196. * @param string $key
  197. * @param string $value
  198. */
  199. private function store($key, $value) {
  200. $this->config->setUserValue($this->uid, 'user_ldap', $key, $value);
  201. }
  202. /**
  203. * Stores the display name in the databae
  204. * @param string $displayName
  205. */
  206. public function storeDisplayName($displayName) {
  207. $this->store('displayName', $displayName);
  208. }
  209. /**
  210. * Stores the LDAP Username in the Database
  211. * @param string $userName
  212. */
  213. public function storeLDAPUserName($userName) {
  214. $this->store('uid', $userName);
  215. }
  216. /**
  217. * @brief checks whether an update method specified by feature was run
  218. * already. If not, it will marked like this, because it is expected that
  219. * the method will be run, when false is returned.
  220. * @param string email | quota | avatar (can be extended)
  221. * @return bool
  222. */
  223. private function wasRefreshed($feature) {
  224. if(isset($this->refreshedFeatures[$feature])) {
  225. return true;
  226. }
  227. $this->refreshedFeatures[$feature] = 1;
  228. return false;
  229. }
  230. /**
  231. * @brief fetches the email from LDAP and stores it as ownCloud user value
  232. * @return null
  233. */
  234. public function updateEmail() {
  235. if($this->wasRefreshed('email')) {
  236. return;
  237. }
  238. $email = null;
  239. $emailAttribute = $this->connection->ldapEmailAttribute;
  240. if(!empty($emailAttribute)) {
  241. $aEmail = $this->access->readAttribute($this->dn, $emailAttribute);
  242. if($aEmail && (count($aEmail) > 0)) {
  243. $email = $aEmail[0];
  244. }
  245. if(!is_null($email)) {
  246. $this->config->setUserValue(
  247. $this->uid, 'settings', 'email', $email);
  248. }
  249. }
  250. }
  251. /**
  252. * @brief fetches the quota from LDAP and stores it as ownCloud user value
  253. * @return null
  254. */
  255. public function updateQuota() {
  256. if($this->wasRefreshed('quota')) {
  257. return;
  258. }
  259. $quota = null;
  260. $quotaDefault = $this->connection->ldapQuotaDefault;
  261. $quotaAttribute = $this->connection->ldapQuotaAttribute;
  262. if(!empty($quotaDefault)) {
  263. $quota = $quotaDefault;
  264. }
  265. if(!empty($quotaAttribute)) {
  266. $aQuota = $this->access->readAttribute($this->dn, $quotaAttribute);
  267. if($aQuota && (count($aQuota) > 0)) {
  268. $quota = $aQuota[0];
  269. }
  270. }
  271. if(!is_null($quota)) {
  272. $this->config->setUserValue($this->uid, 'files', 'quota', $quota);
  273. }
  274. }
  275. /**
  276. * @brief attempts to get an image from LDAP and sets it as ownCloud avatar
  277. * @return null
  278. */
  279. public function updateAvatar() {
  280. if($this->wasRefreshed('avatar')) {
  281. return;
  282. }
  283. $avatarImage = $this->getAvatarImage();
  284. if($avatarImage === false) {
  285. //not set, nothing left to do;
  286. return;
  287. }
  288. $this->image->loadFromBase64(base64_encode($avatarImage));
  289. $this->setOwnCloudAvatar();
  290. }
  291. /**
  292. * @brief sets an image as ownCloud avatar
  293. * @return null
  294. */
  295. private function setOwnCloudAvatar() {
  296. if(!$this->image->valid()) {
  297. $this->log->log('user_ldap', 'jpegPhoto data invalid for '.$this->dn,
  298. \OCP\Util::ERROR);
  299. return;
  300. }
  301. //make sure it is a square and not bigger than 128x128
  302. $size = min(array($this->image->width(), $this->image->height(), 128));
  303. if(!$this->image->centerCrop($size)) {
  304. $this->log->log('user_ldap',
  305. 'croping image for avatar failed for '.$this->dn,
  306. \OCP\Util::ERROR);
  307. return;
  308. }
  309. if(!$this->fs->isLoaded()) {
  310. $this->fs->setup($this->uid);
  311. }
  312. $avatar = $this->avatarManager->getAvatar($this->uid);
  313. $avatar->set($this->image);
  314. }
  315. }