New Module Microsoft Exchange Hosted

Discussion in 'Developers' Forum' started by remy74, May 14, 2013.

  1. remy74

    remy74 New Member

    Dear All,

    We have started a new module, for managing Microsoft Exchange / Active Directory using ISPConfig. The goal of this module is to provide customer control into their Tenancy organization. There is a lot of works, but we are on the good way, and we have do a lot of stuff.
    This module is on 2 parts, one on Windows (using a Windows service to communicate with the AD / Exchange and the database), and the second is on ISPConfig, for displaying, managing Active Directory Objects.

    As this module use a copy of the LDAP database under mysql (done by the windows service) we need to implement complicate SQL query.

    However, we didin't find documentation for ISPConfig for doing that.
    We just see that every Mysql Table must have some columns, like sys_userid, sys_groupid etc..
    How can we do that ? We need to implement "where" to the query, but on the module, we have to select all the table, and the {AUTHSQL} never help .

    Is there a way for doing that ?
    like that :

    Code:
    $liste["name"] 				= "Exchange_details";
    // Database table
    $liste["table"] 			        = "AD_MY_TABLE";
    [B]$liste["where"] 			= "columns='" .  $_REQUEST['id']  ."'";[/B]
    
    Also, we need to use other objects with mysql, for performance, like stored procedure, and views..

    In advance, thanks for your help.

    PS: Of course, when this module will be done, all the sources will be push to the community, include Windows source.
     
  2. till

    till Super Moderator Howtoforge Staff HowtoForge Supporter ISPConfig Developer

    You can override many values or override subfunctions of the list object including the complete "where" part of the sql query. Example from web_domain_list.php:

    Code:
    $list = new list_action;
    $list->SQLExtWhere = "type = 'vhost' AND parent_domain_id = '0'";
    $list->SQLOrderBy = 'ORDER BY domain';
    $list->onLoad();
    The list object is defined in lib/classes/listform_actions.inc.php, its a good place to get a overview of the existing functions. Basically you can override nearly every aspect of the list generation and query building in ispconfig.
     
  3. remy74

    remy74 New Member

    Thanks for your prompt reply !
    This is what we see when we browse the ISPCONFIG class (list form_actions.inc.php)
    We test it, and it's working fine ! Again, thanks for your help !

    Is there a global documentation about all the classes ?
     
  4. till

    till Super Moderator Howtoforge Staff HowtoForge Supporter ISPConfig Developer

    No, not yet. It is planned but we simply did not had the time to write it.

    Basically forms are inherited from tform_actions class and lists from listform_actions class. You can override subfunctions of the form calss similar to the list class, so you can read even data from other sources then mysql. See e.g. the admin/server_config_edit.php file which reads the data that is displayed in the form from a ini style text blob field in mysql (it could have been a file as well or also ldap if you use ldap functions to get data in form of a array / hash in php.
     
    Last edited: May 14, 2013
  5. remy74

    remy74 New Member

    Hi,

    We are on the good way with the module, but we have some problem.
    For example, users have multiple properties to be set / or change.
    But on our module, you are not allowed to change mail address and reset the password, or unlock account etc..
    For the moment, we manage users using a tform with multiple TAB. When we switch from one TAB to another TAB, it's automatically save into the database. This is not what we except.. Is there a possible override to block that ?
    We do not wan't to build each form for each function, and if we have another way..
    Thanks for your help !
     
  6. till

    till Super Moderator Howtoforge Staff HowtoForge Supporter ISPConfig Developer

    This is configurable under System > Interface config.
     
  7. remy74

    remy74 New Member

    Hi All,

    Another question for everybody who knows.. Is there an inside function to convert a integer of byte to MB / GB / TB before display it ?
    We have see :

    Code:
        public function convertSize($value)
        {
            $unit = array('Bytes', 'KB', 'MB', 'GB', 'TB');
            return @round($value/pow(1024, ($i = floor(log($value, 1024)))), 2).' '.$unit[$i];
        }
    under ApsBase, but nothing that could help us.
    We would like to use it for display the value, not set it (in the DB we prefer have the byte value..)
    Maybe with a filter in the tform ?
    If someone have an idea..

    Thanks for your precious help.
     
  8. till

    till Super Moderator Howtoforge Staff HowtoForge Supporter ISPConfig Developer

    There is no api function availbale for that. The places were we use such conversions (e.g. web statistics) it is hard coded. Its a good idea to add it as a filter in the next version.
     
  9. florian030

    florian030 Member HowtoForge Supporter ISPConfig Developer

    I use

    Code:
    function formatBytes($size, $precision = 2) {
            $base=log($size)/log(1024);
            $suffixes=array('','k','M','G','T');
            return round(pow(1024,$base-floor($base)),$precision).$suffixes[floor($base)];
    }
    
    in cron_daily.php to add the Backup-Size of each file to the Database. The patch is avalable in the svn-trunk.
     
  10. remy74

    remy74 New Member

    Thanks for your answer, but what do you mean about this ?
    Do you said that you have implement this ?
     
  11. remy74

    remy74 New Member

    For testing, I'm trying to add this :
    Code:
    function filterField($field_name, $field_value, $filters, $filter_event) {
    
                            global $app;
                            $returnval = $field_value;
    
                            //* Loop trough all filters
                            foreach($filters as $filter) {
                                    if($filter['event'] == $filter_event) {
                                            switch ($filter['type']) {
                                                    case 'TOLOWER':
                                                            $returnval = strtolower($returnval);
                                                    break;
                                                    case 'TOUPPER':
                                                            $returnval = strtoupper($returnval);
                                                    break;
                                                    case 'IDNTOASCII':
                                                            $returnval = $app->functions->idn_encode($returnval);
                                                    break;
                                                    case 'IDNTOUTF8':
                                                            $returnval = $app->functions->idn_decode($returnval);
                                                    break;
                                                    case 'FORMATED_BYTES':
                                                            $unit = array('Bytes', 'KB', 'MB', 'GB', 'TB');
                                                            $returnval= @round($value/pow(1024, ($i = floor(log($returnval, 1024)))), 2).' '.$unit[$i];
                                                    //   In the next try, will implement this on the functions class ..   
                                                   // $returnval = $app->functions->convertSize($returnval);
                                                    break;          
                                                    default:
                                                            $this->errorMessage .= "Unknown Filter: ".$filter['type'];
                                                    break;
    
                                            }
                                    }
                            }
                return $returnval;
            }
    
    on the tform.inc files ..
    And on the tfrom file module :
    Code:
    'filters'   => array( 0 => array( 'event' => 'SHOW',
                                                  'type' => 'FORMATED_BYTES')
    											  ),                     
    but no lucky, not working.. Is we forget something else ?
     
    Last edited: May 28, 2013
  12. remy74

    remy74 New Member

    Ok it's working, implement this on functions.inc.php (before the last '}' of the file) :

    Code:
    	public function formatBytes($size, $precision = 2) {
            $base=log($size)/log(1024);
            $suffixes=array('','k','M','G','T');
            return round(pow(1024,$base-floor($base)),$precision).$suffixes[floor($base)];	
            
    		}
    And on tform.inc.php :
    Code:
           function filterField($field_name, $field_value, $filters, $filter_event) {
    
    			global $app;
    			$returnval = $field_value;
    				
    			//* Loop trough all filters
    			foreach($filters as $filter) {
    				if($filter['event'] == $filter_event) {
    					switch ($filter['type']) {
    						case 'TOLOWER':
    							$returnval = strtolower($returnval);
    						break;
    						case 'TOUPPER':
    							$returnval = strtoupper($returnval);
    						break;
    						case 'IDNTOASCII':
    							$returnval = $app->functions->idn_encode($returnval);
    						break;
    						case 'IDNTOUTF8':
    							$returnval = $app->functions->idn_decode($returnval);
    						break;
    						case 'BYTES':
                                                    // format the value for bytes, return a TEXT / VARCHAR, not integer !
    							$returnval = $app->functions->formatBytes($returnval);
    						break;	
    						default:
    							$this->errorMessage .= "Unknown Filter: ".$filter['type'];
    						break;
    						
    					}
    				}
    			}
                return $returnval;
            }
    Maybe this will help someone else.
     
  13. florian030

    florian030 Member HowtoForge Supporter ISPConfig Developer

    Not reallay - it´s implemented in cron_daily.php but not as an api-function (btw: thanks for writing the patch).

    I only posted my code as it allows to define the precision.
     
  14. remy74

    remy74 New Member

    Ok, thanks for your reply. It's real simple patch, and it's working for me because only used for "SHOW" events not "SAVE".
    So the patch is not complete (I think..)
    When I will have time, will try to see the other event.. :D
     
  15. Ben

    Ben New Member Moderator HowtoForge Supporter ISPConfig Developer

    Good work, seems to be an interesting plugin.

    But... :)

    Eventhough this was just sample code, would you mind validating and escaping all external input, e.g. here to validate $_REQUEST['id'] for beein just numbers or characters what ever will be the right syntax, and if the valid charset could lead to sql injection or similar, you should escape it additionally.
    Btw this should happen for all data that you can not control, in this case also for data you gather from and to the exchange side.
     
  16. remy74

    remy74 New Member

    Yes, we knows that. In all forms, we put validators, and when we extract data from Exchange (ActiveDirectory) we also validate the format.

    We try our best, but we will also need other "eyes" to be sure that all is conform for ISPConfig and the security.
     
  17. Ben

    Ben New Member Moderator HowtoForge Supporter ISPConfig Developer

    Good to read. If there is code ready, just provide a link where to look at it.

    @Falko / Till: There isn't a kind of security best practices in context of ISPConfig3 module development, so that not every interested developer needs to read all the OWASP stuff totally as probably some of those issues are solve by helper functions. So the dev' "just" needs to unterstand the issue and why to use such helpers.
     
  18. remy74

    remy74 New Member

    Hi all,
    I have another question about "validators".

    At what time does they operate ?
    For example :

    We use the beforeUpdate to set others SQL, and we use $app->tform->getDataRecord($this->id) to get old informations and compare it to the new to be sure that we need to update it or not.

    We have also put some validator on all forms, but the validators returns errors on update (I guess).

    But if we try this way, when validators returns errors, the beforeUpdate was already called. And if we use AfterUpdate, the old Data is = new data..

    Do we can check with other way the old / new data ? or do we have an option to check all validators beforeUpdate ?

    Hope this is clear for who reading this...

    For information, the module is in multiple parts :

    - Windows service
    => read / write ActiveDirectory / Set Exchange Command
    => read / write to mysql

    - ISPConfig module
    => read / write mysql using ISPConfig Class
    => read/ write to others mysql using custom query for command to Windows Service. (with sys_group, sys_userid etc..)


    Thanks all in advance
     
  19. remy74

    remy74 New Member

    In fact, we just need to knows if there is a simple function to track which data was modified, after they are validate.
     
  20. till

    till Super Moderator Howtoforge Staff HowtoForge Supporter ISPConfig Developer

    The data si saved in the onUpdateSave function of the tform_actions class. You can either completely override that function in case you want to store data in another source like a file, ldap or similar instaed of mysql or you override it and call the parent function after you executed your custom code.

    Example:

    Code:
    myform extends tform_actions {
    
    function onUpdateSave($sql) {
    
    ... do something ...
    
    parent::onUpdateSave($sql);
    
    }
    
    
    }
    if you want to get the changes of a record, use the diffrec function of the mysql library. This function is used by ispconfig to detect which differences have to be saved into the sys_datalog for processing on the server.
     
    Last edited: May 29, 2013

Share This Page