00a7a8c6be6b346afdd2a7cb24d1f69b37d5b2f5
[tine20] / tests / tine20 / Tinebase / AuthTest.php
1 <?php
2 /**
3  * Tine 2.0 - http://www.tine20.org
4  * 
5  * @package     Tinebase
6  * @subpackage  Auth
7  * @license     http://www.gnu.org/licenses/agpl.html
8  * @copyright   Copyright (c) 2009-2016 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Jonas Fischer <j.fischer@metaways.de>
10  * 
11  * @todo        split this
12  */
13
14 /**
15  * Test helper
16  */
17 require_once dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'TestHelper.php';
18
19 /**
20  * Test class for Tinebase_Auth_Abstract
21  */
22 class Tinebase_AuthTest extends TestCase
23 {
24     /**
25      * @var array test objects
26      */
27     protected $_objects = array();
28     
29     /**
30      * @var mixed
31      */
32     protected $_originalBackendConfiguration = null;
33     
34     /**
35      * @var mixed
36      */
37     protected $_originalBackendType = null;
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         parent::setUp();
48
49         $this->_originalBackendConfiguration = Tinebase_Auth::getBackendConfiguration();
50         $this->_originalBackendType = Tinebase_Auth::getConfiguredBackend();
51     }
52
53     /**
54      * Tears down the fixture
55      * This method is called after a test is executed.
56      *
57      * @access protected
58      */
59     protected function tearDown()
60     {
61         // this needs to be done because Tinebase_Auth & Tinebase_Config use caching mechanisms
62         Tinebase_Auth::setBackendType($this->_originalBackendType);
63         Tinebase_Auth::deleteBackendConfiguration();
64         Tinebase_Auth::setBackendConfiguration($this->_originalBackendConfiguration);
65         Tinebase_Auth::saveBackendConfiguration();
66         Tinebase_Auth::getInstance()->setBackend();
67         
68         parent::tearDown();
69     }
70
71     /**
72      * testSaveBackendConfiguration
73      */
74     public function testSaveBackendConfiguration()
75     {
76         Tinebase_Auth::setBackendType(Tinebase_Auth::LDAP);
77      
78         $rawConfigBefore = Tinebase_Config::getInstance()->get(Tinebase_Config::AUTHENTICATIONBACKEND);
79         $key = 'host';
80         $testValue = 'phpunit-test-host2';
81         Tinebase_Auth::setBackendConfiguration($testValue, $key);
82         Tinebase_Auth::saveBackendConfiguration();
83         $rawConfigAfter = Tinebase_Config::getInstance()->get(Tinebase_Config::AUTHENTICATIONBACKEND);
84         $this->assertNotEquals($rawConfigBefore, $rawConfigAfter);
85     }
86     
87     /**
88      * 
89      * testSetBackendConfiguration
90      */
91     public function testSetBackendConfiguration()
92     {
93         Tinebase_Auth::setBackendType(Tinebase_Auth::LDAP);
94      
95         $key = 'host';
96         $testValue = 'phpunit-test-host';
97         Tinebase_Auth::setBackendConfiguration($testValue, $key);
98         $this->assertEquals($testValue, Tinebase_Auth::getBackendConfiguration($key));
99
100         $testValues = array('host' => 'phpunit-test-host2',
101            'username' => 'cn=testcn,ou=teestou,o=testo',
102            'password' => 'secret'
103         );
104         Tinebase_Auth::setBackendConfiguration($testValues);
105         foreach ($testValues as $key => $testValue) {
106             $this->assertEquals($testValue, Tinebase_Auth::getBackendConfiguration($key));
107         }
108     }
109     
110     /**
111      * testDeleteBackendConfiguration
112      */
113     public function testDeleteBackendConfiguration()
114     {
115         Tinebase_Auth::setBackendType(Tinebase_Auth::LDAP);
116      
117         $key = 'host';
118         Tinebase_Auth::setBackendConfiguration('configured-host', $key);
119         $this->assertEquals('configured-host', Tinebase_Auth::getBackendConfiguration($key, 'default-host'));
120         Tinebase_Auth::deleteBackendConfiguration($key);
121         $this->assertEquals('default-host', Tinebase_Auth::getBackendConfiguration($key, 'default-host'));
122         
123         $configOptionsCount = count(Tinebase_Auth::getBackendConfiguration());
124         Tinebase_Auth::deleteBackendConfiguration('non-existing-key');
125         $this->assertEquals($configOptionsCount, count(Tinebase_Auth::getBackendConfiguration()));
126         
127         Tinebase_Auth::setBackendConfiguration('phpunit-dummy-value', $key);
128         $this->assertTrue(count(Tinebase_Auth::getBackendConfiguration()) > 0);
129         Tinebase_Auth::deleteBackendConfiguration();
130         $this->assertTrue(count(Tinebase_Auth::getBackendConfiguration()) == 0);
131     }
132     
133     /**
134      * testGetBackendConfigurationDefaults
135      */
136     public function testGetBackendConfigurationDefaults()
137     {
138         $defaults = Tinebase_Auth::getBackendConfigurationDefaults();
139         $this->assertTrue((isset($defaults[Tinebase_Auth::SQL]) || array_key_exists(Tinebase_Auth::SQL, $defaults)));
140         $this->assertTrue((isset($defaults[Tinebase_Auth::LDAP]) || array_key_exists(Tinebase_Auth::LDAP, $defaults)));
141         $this->assertTrue(is_array($defaults[Tinebase_Auth::LDAP]));
142         $this->assertFalse((isset($defaults['host']) || array_key_exists('host', $defaults)));
143         
144         $defaults = Tinebase_Auth::getBackendConfigurationDefaults(Tinebase_Auth::LDAP);
145         $this->assertTrue((isset($defaults['host']) || array_key_exists('host', $defaults)));
146         $this->assertFalse((isset($defaults[Tinebase_Auth::LDAP]) || array_key_exists(Tinebase_Auth::LDAP, $defaults)));
147     }
148     
149     /**
150      * test imap authentication
151      */
152     public function testImapAuth()
153     {
154         // use imap config for the auth config
155         $imapConfig = Tinebase_Config::getInstance()->get(Tinebase_Config::IMAP, new Tinebase_Config_Struct())->toArray();
156         
157         if (empty($imapConfig)) {
158              $this->markTestSkipped('No IMAP config found.');
159         }
160         
161         $authConfig = array(
162             'host'      => $imapConfig['host'],
163             'port'      => $imapConfig['port'],
164             'ssl'       => $imapConfig['ssl'],
165             'domain'    => $imapConfig['domain'],
166         );
167         Tinebase_Auth::setBackendType(Tinebase_Auth::IMAP);
168         Tinebase_Auth::setBackendConfiguration($authConfig);
169         Tinebase_Auth::saveBackendConfiguration();
170         Tinebase_Auth::getInstance()->setBackend();
171         
172         $this->assertEquals(Tinebase_Auth::IMAP, Tinebase_Auth::getConfiguredBackend());
173
174         $testCredentials = TestServer::getInstance()->getTestCredentials();
175         
176         // valid authentication
177         $authResult = Tinebase_Auth::getInstance()->authenticate($testCredentials['username'], $testCredentials['password']);
178         $this->assertTrue($authResult->isValid());
179         
180         // invalid authentication
181         $authResult = Tinebase_Auth::getInstance()->authenticate($testCredentials['username'], 'some pw');
182         $this->assertFalse($authResult->isValid());
183         $this->assertEquals(Tinebase_Auth::FAILURE_CREDENTIAL_INVALID, $authResult->getCode());
184         $this->assertEquals(array('Invalid credentials for user ' . $this->_getEmailAddress(), ''), $authResult->getMessages());
185     }
186     
187     /**
188      * test credential cache cleanup
189      */
190     public function testClearCredentialCacheTable()
191     {
192         // add dummy record to credential cache
193         $id = Tinebase_Record_Abstract::generateUID();
194         $db = Tinebase_Core::getDb();
195         $oneMinuteAgo = Tinebase_DateTime::now()->subMinute(1)->format(Tinebase_Record_Abstract::ISO8601LONG);
196         $data = array(
197             'id'            => $id,
198             'cache'         => Tinebase_Record_Abstract::generateUID(),
199             'creation_time' => $oneMinuteAgo,
200             'valid_until'   => $oneMinuteAgo,
201         );
202         $table = SQL_TABLE_PREFIX . 'credential_cache';
203         Tinebase_Core::getDb()->insert($table, $data);
204         
205         Tinebase_Auth_CredentialCache::getInstance()->clearCacheTable();
206         
207         $result = $db->fetchCol('SELECT id FROM ' . $db->quoteIdentifier($table) . ' WHERE ' . $db->quoteInto($db->quoteIdentifier('valid_until') .' < ?', Tinebase_DateTime::now()->format(Tinebase_Record_Abstract::ISO8601LONG)));
208         $this->assertNotContains($id, $result);
209     }
210
211     /**
212      * @see 0011366: support privacyIdea authentication
213      */
214     public function testSecondFactor()
215     {
216         $result = Tinebase_Auth::validateSecondFactor('phil', 'phil', array(
217             'active' => true,
218             'provider' => 'Mock',
219             'url' => 'https://localhost/validate/check',
220         ));
221         $this->assertEquals(Tinebase_Auth::SUCCESS, $result);
222     }
223
224     /**
225      * @see 0013272: add pin column, backend and config
226      */
227     public function testSecondFactorTine20()
228     {
229         $user = Tinebase_Core::getUser();
230         Tinebase_User::getInstance()->setPin($user, '1234');
231         $result = Tinebase_Auth::validateSecondFactor($user->accountLoginName, '1234', array(
232             'active' => true,
233             'provider' => 'Tine20',
234         ));
235         $this->assertEquals(Tinebase_Auth::SUCCESS, $result);
236     }
237
238     /**
239      * @see 0013328: protect applications with second factor
240      */
241     public function testSecondFactorAppProtection()
242     {
243         // set configs
244         Tinebase_Config::getInstance()->set(Tinebase_Config::SECONDFACTORPROTECTEDAPPS, array(
245             'Tasks'
246         ));
247         Tinebase_Config::getInstance()->set(Tinebase_Config::AUTHENTICATIONSECONDFACTOR, array(
248             'active' => true,
249             'provider' => 'Tine20',
250         ));
251
252         // set pin
253         $user = Tinebase_Core::getUser();
254         Tinebase_User::getInstance()->setPin($user, '1234');
255
256         // try to access app
257         try {
258             $tasks = Tasks_Controller_Task::getInstance()->getAll();
259             self::fail('it should not be possible to access app without PIN');
260         } catch (Tinebase_Exception $te) {
261             // check exception
262             self::assertTrue($te instanceof Tinebase_Exception_SecondFactorRequired);
263         }
264
265         // validate pin
266         $json = new Tinebase_Frontend_Json();
267         $json->validateSecondFactor('1234');
268
269         // try to access app again
270         $result = Tasks_Controller_Task::getInstance()->getAll();
271         self::assertGreaterThanOrEqual(0, count($result));
272     }
273 }