f4ee2d2f02ed7514c55b6f6ea75a861147bc8a26
[tine20] / scripts / syncuuids / lib / Sync.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Sync
6  * @author      Philipp Schüle <p.schuele@metaways.de
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2008-2015 Metaways Infosystems GmbH (http://www.metaways.de)
9  */
10
11 /**
12  * class documentation
13  *
14  * @package     Sync
15  */
16 class Sync 
17 {
18     /**
19      * configuration
20      * 
21      * @var Zend_Config
22      */
23     protected $_config = NULL;
24     
25     /**
26      * logger
27      * 
28      * @var Zend_Log
29      */
30     protected $_logger = NULL;
31     
32     /**
33      * ldap connector
34      * 
35      * @var Zend_Ldap
36      */
37     protected $_ldap = NULL;
38
39    /**
40     * the basic group ldap filter (for example the objectclass)
41     *
42     * default LDAP:  'objectclass=posixgroup'
43     * Samba:         'objectclass=group'
44     *
45     * @var string
46     */
47     protected $_groupBaseFilter = 'objectclass=group';
48     
49    /**
50     * the basic user ldap filter (for example the objectclass)
51     *
52     * default LDAP:  'objectclass=posixaccount'
53     * Samba:         'objectclass=user'
54     *
55     * @var string
56     */
57     protected $_userBaseFilter = 'objectclass=user';
58
59     /**
60      * username property
61      *
62      * default LDAP: 'uid'
63      * Samba:        'samaccountname'
64      *
65      * @var string
66      */
67     protected $_usernameProperty = 'samaccountname';
68
69     /**
70      * uuid property
71      *
72      * default LDAP: 'entryuuid'
73      * Samba:        'objectguid'
74      *
75      * @var string
76      */
77     protected $_uuidProperty = 'objectguid';
78
79     /**
80     * the tine user backend
81     *
82     * @var Tinebase_User_Sql
83     */
84     protected $_tineUserBackend = NULL;
85     
86     /**
87      * the tine group backend
88     *
89     * @var Tinebase_Group_Sql
90     */
91     protected $_tineGroupBackend = NULL;
92     
93     /**
94     * the basic user search scope
95     *
96     * @var integer
97     */
98     protected $_userSearchScope = Zend_Ldap::SEARCH_SCOPE_SUB;
99     
100     /**
101     * the basic group search scope
102     *
103     * @var integer
104     */
105     protected $_groupSearchScope     = Zend_Ldap::SEARCH_SCOPE_SUB;
106     
107     /**
108      * the constructor
109      */
110     public function __construct()
111     {
112         $this->_initSettings();
113         $this->_initConfig();
114         $this->_initLogger();
115         $this->_initLdap();
116         $this->_initTineBackends();
117         
118         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' init complete');
119     }
120     
121     /**
122      * init php settings
123      */
124     protected function _initSettings()
125     {
126         error_reporting(E_COMPILE_ERROR | E_CORE_ERROR | E_ERROR | E_PARSE);
127         ini_set('display_errors', 1);
128         ini_set('log_errors', 1);
129         set_error_handler('Tinebase_Core::errorHandler', E_ALL);
130         
131         ini_set('iconv.internal_encoding', 'utf-8');
132     }
133     
134     /**
135      * init config
136      */
137     protected function _initConfig()
138     {
139         $configData = include('conf.php');
140         if ($configData === false) {
141             die ('central configuration file config.inc.php not found in includepath: ' . get_include_path());
142         }
143         $this->_config = new Zend_Config($configData);
144         
145         if (! $this->_config->inputfile) {
146             die('need inputfile in config');
147         }
148     }
149
150     /**
151      * init config
152      */
153     protected function _initLogger()
154     {
155         $this->_logger = new Zend_Log();
156         if ($this->_config->logfile) {
157             $writer = new Zend_Log_Writer_Stream($this->_config->logfile);
158         } else {
159             $writer = new Zend_Log_Writer_Null;
160         }
161         $this->_logger->addWriter($writer);
162         
163         if ($this->_config->loglevel) {
164             $filter = new Zend_Log_Filter_Priority($this->_config->loglevel);
165             $this->_logger->addFilter($filter);
166         }
167     }
168     
169     /**
170      * returns config
171      * 
172      * @return Zend_Config
173      */
174     public function getConfig()
175     {
176         return $this->_config;
177     }
178     
179     /**
180      * init ldap
181      */
182     protected function _initLdap()
183     {
184         if (! $this->_config->ldap || ! $this->_config->ldap->baseDn) {
185             throw new Exception('ldap config section or basedn missing');
186         }
187         
188         $this->_ldap = new Zend_Ldap($this->_config->ldap->toArray());
189         $this->_ldap->bind();
190         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' LDAP initialized');
191     }
192
193     /**
194     * init tine backends
195     */
196     protected function _initTineBackends()
197     {
198         Tinebase_Core::setupConfig();
199         Tinebase_Core::setupDatabaseConnection();
200         
201         $this->_tineUserBackend = new Tinebase_User_Sql();
202         $this->_tineGroupBackend = new Tinebase_Group_Sql();
203     }
204     
205     /**
206      * sync user/group ids in db dump
207      */
208     public function doSync()
209     {
210         $userMapping = $this->_getUserMapping();
211         $groupMapping = $this->_getGroupMapping();
212         
213         if ($this->_config->dryrun) {
214             echo "user mapping:\n" . print_r($userMapping, TRUE);
215             echo "group mapping:\n" . print_r($groupMapping, TRUE);
216         } else {
217             $this->_syncIdsInDump(array_merge($userMapping, $groupMapping));
218             $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Sync finished.');
219         }
220     }
221     
222     /**
223      * read ldap / get users from tine an create mapping
224      * 
225      * @return array
226      */
227     protected function _getUserMapping()
228     {
229         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Fetching user mapping ...');
230         
231         $filter = Zend_Ldap_Filter::andFilter(
232             Zend_Ldap_Filter::string($this->_userBaseFilter)
233         );
234         $mapping = array();
235         $ldapUsers = $this->_ldap->search($filter, $this->_config->ldap->baseDn, $this->_userSearchScope, array('*', '+'));
236         foreach ($ldapUsers as $user) {
237             $username = $user[$this->_usernameProperty][0];
238             $ldapUuid = ($this->_uuidProperty === 'objectguid')
239                 ? Tinebase_Ldap::decodeGuid($user['objectguid'][0])
240                 : $user[$this->_uuidProperty][0];
241
242             try {
243                 $tineUser = $this->_tineUserBackend->getFullUserByLoginName($username);
244                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' User ' . $username . ': ' . $tineUser->getId() . ' -> ' . $ldapUuid);
245                 $mapping[$tineUser->getId()] = $ldapUuid;
246             } catch (Tinebase_Exception_NotFound $tenf) {
247                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' User ' . $username . ' not found.');
248             }
249         }
250         
251         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Found ' . count($mapping) . ' users for the mapping.');
252         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($mapping, TRUE));
253         
254         return $mapping;
255     }
256
257     /**
258      * read ldap / get users and groups from tine an create mapping
259      * 
260      * @return array
261      */
262     protected function _getGroupMapping()
263     {
264         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Fetching user mapping ...');
265         
266         $filter = Zend_Ldap_Filter::andFilter(
267             Zend_Ldap_Filter::string($this->_groupBaseFilter)
268         );
269         $mapping = array();
270         $groupNameMapping = ($this->_config->groupNameMapping) ? $this->_config->groupNameMapping->toArray() : array();
271         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group name mapping: ' . print_r($groupNameMapping, TRUE));
272         $ldapGroups = $this->_ldap->search($filter, $this->_config->ldap->baseDn, $this->_groupSearchScope, array('*', '+'));
273         foreach ($ldapGroups as $group) {
274             $groupname = (isset($groupNameMapping[$group['cn'][0]])) ? $groupNameMapping[$group['cn'][0]] : $group['cn'][0];
275             $ldapUuid = ($this->_uuidProperty === 'objectguid')
276                 ? Tinebase_Ldap::decodeGuid($group['objectguid'][0])
277                 : $group[$this->_uuidProperty][0];
278
279             try {
280                 $tineGroup = $this->_tineGroupBackend->getGroupByName($groupname);
281                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group ' . $groupname . ' (' .$group['cn'][0] . '): ' . $tineGroup->getId() . ' -> ' . $ldapUuid);
282                 $mapping[$tineGroup->getId()] = $ldapUuid;
283             } catch (Tinebase_Exception_Record_NotDefined $tenf) {
284                 // @todo should be: Tinebase_Exception_NotFound 
285                 $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' Group ' . $groupname . ' (' .$group['cn'][0] . '): ' . $tenf->getMessage());
286             }
287         }
288         
289         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Found ' . count($mapping) . ' groups for the mapping.');
290         $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($mapping, TRUE));
291         
292         return $mapping;
293     }
294     
295     /**
296      * syncs the ids in a sql dump file
297      * 
298      * @param array $mapping
299      */
300     protected function _syncIdsInDump($mapping)
301     {
302         // use mapping for str_replace
303         if (! file_exists($this->_config->inputfile)) {
304             die('file does not exist');
305         }
306         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Reading input file: ' . $this->_config->inputfile);
307         $input = file_get_contents($this->_config->inputfile);
308         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Replacing ids ...');
309         $output = str_replace(array_keys($mapping), array_values($mapping), $input);
310         
311         $filename = ($this->_config->outputfile) ? $this->_config->outputfile : 'synced.sql';
312         $this->_logger->info(__METHOD__ . '::' . __LINE__ . ' Writing to file: ' . $filename);
313         file_put_contents($filename, $output);
314     }
315 }