0013326: use userid@instancename and for email account name
[tine20] / tests / tine20 / Tinebase / User / EmailUser / Imap / DovecotTest.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Tinebase
6  * @subpackage  User
7  * @license     http://www.gnu.org/licenses/agpl.html
8  * @copyright   Copyright (c) 2009-2016 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Philipp Schüle <p.schuele@metaways.de>
10  */
11
12 /**
13  * Test helper
14  */
15 require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . DIRECTORY_SEPARATOR . 'TestHelper.php';
16
17 /**
18  * Test class for Tinebase_DovecotTest
19  */
20 class Tinebase_User_EmailUser_Imap_DovecotTest extends PHPUnit_Framework_TestCase
21 {
22     /**
23      * email user backend
24      *
25      * @var Tinebase_User_Plugin_Abstract
26      */
27     protected $_backend = null;
28
29     /**
30      * @var array test objects
31      */
32     protected $_objects = array();
33
34     /**
35      * @var array config
36      */
37     protected $_config;
38
39     /**
40      * Sets up the fixture.
41      * This method is called before a test is executed.
42      *
43      * @access protected
44      */
45     protected function setUp()
46     {
47         $this->_config = Tinebase_Config::getInstance()->get(Tinebase_Config::IMAP,
48             new Tinebase_Config_Struct())->toArray();
49         if (!isset($this->_config['backend']) || !('Imap_' . ucfirst($this->_config['backend']) == Tinebase_EmailUser::IMAP_DOVECOT) || $this->_config['active'] != true) {
50             $this->markTestSkipped('Dovecot MySQL backend not configured or not enabled');
51         }
52
53         if (Tinebase_User::getConfiguredBackend() === Tinebase_User::ACTIVEDIRECTORY) {
54             // error: Zend_Ldap_Exception: 0x44 (Already exists; 00002071: samldb: Account name (sAMAccountName)
55             // 'tine20phpunituser' already in use!): adding: cn=PHPUnit User Tine 2.0,cn=Users,dc=example,dc=org
56             $this->markTestSkipped('skipped for ad backends as it does not allow duplicate CNs');
57         }
58
59         $this->_backend = Tinebase_EmailUser::getInstance(Tinebase_Config::IMAP);
60
61         $personas = Zend_Registry::get('personas');
62         $this->_objects['user'] = clone $personas['jsmith'];
63         //$this->_objects['user']->setId(Tinebase_Record_Abstract::generateUID());
64
65         $this->_objects['addedUsers'] = array();
66         $this->_objects['fullUsers'] = array();
67     }
68
69     /**
70      * Tears down the fixture
71      * This method is called after a test is executed.
72      *
73      * @access protected
74      */
75     protected function tearDown()
76     {
77         // delete email account
78         foreach ($this->_objects['addedUsers'] as $user) {
79             $this->_backend->inspectDeleteUser($user);
80         }
81
82         foreach ($this->_objects['fullUsers'] as $user) {
83             Tinebase_User::getInstance()->deleteUser($user);
84         }
85     }
86
87     /**
88      * try to add an email account
89      */
90     public function testAddEmailAccount()
91     {
92         $emailUser = clone $this->_objects['user'];
93         $emailUser->imapUser = new Tinebase_Model_EmailUser(array(
94             'emailPassword' => Tinebase_Record_Abstract::generateUID(),
95             'emailUID' => '1000',
96             'emailGID' => '1000'
97         ));
98
99         $this->_backend->inspectAddUser($this->_objects['user'], $emailUser);
100         $this->_objects['addedUsers']['emailUser'] = $this->_objects['user'];
101
102         $this->_assertImapUser();
103         return $this->_objects['user'];
104     }
105
106     /**
107      * try to update an email account
108      */
109     public function testUpdateAccount()
110     {
111         // add smtp user
112         $user = $this->testAddEmailAccount();
113
114         // update user
115         $user->imapUser->emailMailQuota = 600;
116
117         $this->_backend->inspectUpdateUser($this->_objects['user'], $user);
118         $this->_assertImapUser(array('emailMailQuota' => '600'));
119     }
120
121     /**
122      * asserts that imapUser object contains the correct data
123      *
124      * @param array $additionalExpectations
125      */
126     protected function _assertImapUser($additionalExpectations = array())
127     {
128         $this->assertEquals(array_merge(array(
129             'emailUserId' => $this->_objects['user']->getId(),
130             'emailUsername' => $this->_objects['user']->imapUser->emailUsername,
131             'emailMailQuota' => null,
132             'emailUID' => !empty($this->_config['dovecot']['uid']) ? $this->_config['dovecot']['uid'] : '1000',
133             'emailGID' => !empty($this->_config['dovecot']['gid']) ? $this->_config['dovecot']['gid'] : '1000',
134             'emailLastLogin' => null,
135             'emailMailSize' => 0,
136             'emailSieveSize' => null,
137             'emailPort' => $this->_config['port'],
138             'emailSecure' => $this->_config['ssl'],
139             'emailHost' => $this->_config['host']
140         ), $additionalExpectations), $this->_objects['user']->imapUser->toArray());
141     }
142
143     /**
144      * testSavingDuplicateAccount
145      *
146      * @see 0006546: saving user with duplicate imap/smtp user entry fails
147      */
148     public function testSavingDuplicateAccount()
149     {
150         $user = $this->_addUser();
151         $userId = $user->getId();
152
153         // delete user in tine accounts table
154         $userBackend = new Tinebase_User_Sql();
155         $userBackend->deleteUserInSqlBackend($userId);
156
157         // create user again
158         unset($user->accountId);
159         $newUser = Tinebase_User::getInstance()->addUser($user);
160         $this->_objects['fullUsers'] = array($newUser);
161
162         $this->assertNotEquals($userId, $newUser->getId());
163         $this->assertTrue(isset($newUser->imapUser), 'imapUser data not found: ' . print_r($newUser->toArray(), true));
164     }
165
166     /**
167      * add user with email data
168      *
169      * @param string $username
170      * @return Tinebase_Model_FullUser
171      */
172     protected function _addUser($username = null)
173     {
174         $user = TestCase::getTestUser();
175         if ($username) {
176             $user->accountLoginName = $username;
177         }
178         $user->imapUser = new Tinebase_Model_EmailUser(array(
179             'emailPassword' => Tinebase_Record_Abstract::generateUID(),
180             'emailUID' => '1000',
181             'emailGID' => '1000'
182         ));
183         $user = Tinebase_User::getInstance()->addUser($user);
184         $this->_objects['fullUsers'] = array($user);
185
186         return $user;
187     }
188
189     /**
190      * try to set password
191      */
192     public function testSetPassword()
193     {
194         $user = $this->testAddEmailAccount();
195
196         $newPassword = Tinebase_Record_Abstract::generateUID();
197         $this->_backend->inspectSetPassword($this->_objects['user']->getId(), $newPassword);
198
199         // fetch email pw from db
200         $dovecot = Tinebase_User::getInstance()->getSqlPlugin(Tinebase_EmailUser_Imap_Dovecot::class);
201         $rawDovecotUser = $dovecot->getRawUserById($user);
202         $hashPw = new Hash_Password();
203         $this->assertTrue($hashPw->validate($rawDovecotUser['password'], $newPassword), 'password mismatch');
204     }
205
206     /**
207      * testDuplicateUserId
208      *
209      * @see 0007218: Duplicate userid in dovecot_users
210      */
211     public function testDuplicateUserId()
212     {
213         $emailDomain = TestServer::getPrimaryMailDomain();
214         $user = $this->_addUser('testuser@' . $emailDomain);
215
216         // update user login name
217         $user->accountLoginName = 'testuser';
218         $user = Tinebase_User::getInstance()->updateUser($user);
219
220         $dovecot = Tinebase_User::getInstance()->getSqlPlugin(Tinebase_EmailUser_Imap_Dovecot::class);
221         $rawDovecotUser = $dovecot->getRawUserById($user);
222         self::assertEquals($user->getId() . '@' . $this->_config['instanceName'], $rawDovecotUser['username'],
223             'username has not been updated in dovecot user table ' . print_r($rawDovecotUser, true));
224     }
225
226     /**
227      * testInstanceName
228      *
229      * @see 0013326: use userid@instancename and for email account name
230      *
231      * ALTER TABLE `dovecot_users` ADD `instancename` VARCHAR(80) NULL AFTER `username`, ADD INDEX `instancename` (`instancename`);
232      */
233     public function testInstanceName()
234     {
235         // check if is instanceName in config
236         if (empty($this->_config['instanceName'])) {
237             self::markTestSkipped('no instanceName set in config');
238         }
239
240         $user = $this->_addUser();
241
242         // check email tables (username + instancename)
243         $dovecot = Tinebase_User::getInstance()->getSqlPlugin(Tinebase_EmailUser_Imap_Dovecot::class);
244         $rawDovecotUser = $dovecot->getRawUserById($user);
245
246         self::assertTrue(is_array($rawDovecotUser));
247         self::assertEquals($user->getId() . '@' . $this->_config['instanceName'], $rawDovecotUser['username']);
248         self::assertTrue(isset($rawDovecotUser['instancename']), 'instancename missing: ' . print_r($rawDovecotUser, true));
249         self::assertEquals($this->_config['instanceName'], $rawDovecotUser['instancename']);
250     }
251 }