Example #1
0
 /**
  * Get the default address list for the domain forest
  *
  * @return		Object		The default global address list
  */
 public function defaultGAL()
 {
     if ($this->gal instanceof Object) {
         return $this->gal;
     }
     $task = new \ADX\Core\Task(Enums\Operation::OpSearch, $this->link);
     $gal = $task->base(static::$base)->filter(q::a(['objectCategory' => 'msExchConfigurationContainer']))->attributes('globalAddressList')->run()->first();
     $this->gal = Object::read($gal->globalAddressList(0), static::$attributes, $this->link);
     return $this->gal;
 }
Example #2
0
 /**
  * Get all mailbox stores for a particular Exchange server
  *
  * @param		Object|string		The Exchange server for which to return mailbox stores
  *
  * @return		Result|mixed		The Result containing all the matched objects or whatever the {@link self::_process_result()} returns
  */
 public function for_server($exchangeServer = null)
 {
     $serverFilter = $exchangeServer !== null ? q::a(['msExchOwningServer' => "{$exchangeServer}"]) : null;
     return $this->where($serverFilter);
 }
Example #3
0
 /**
  * Pull changes from Active Directory for a given query
  *
  * Use this method to set up a search query and later get all changed objects
  * for that query. This method returns a special {@link Delta} object that preserves
  * your search configuration and you use this object for consequent
  * searches. It also contains your search results. When you run the method for the first time,
  * it behaves as if you performed just an ordinary search, but on consequent searches,
  * it only returns objects that were modified or deleted since you last ran the search query.
  *
  * <br>
  *
  * <p class='alert'>Note that due to the way this feature is implemented it is impossible to
  * search for objects where only specific attributes have been modified - the method returns all objects
  * that were modified in any way since your last execution and it is your task to determine if
  * the changes happened on attributes that you are interested in.</p>
  * <br>
  *
  * This method takes two possible forms of arguments:<br>
  * When you run it for the first time, you pass the search parameters
  * as for any other ldap search query - the search filter, the list of attributes to be
  * returned and a fully configured {@link Link} instance.
  *
  * <br>
  *
  * For all consecutive executions, you only pass the {@link Delta} instance
  * that you got when you ran the method for the first time and, again, a configured {@link Link}
  * instance.
  *
  * <h2>Example:</h2>
  * To watch for changes on all users in your domain:
  * <code>
  * // Establish connection to your directory server
  * $link = new Link( 'example.com' );
  * $link->bind( '*****@*****.**', 'SecretPwd' );
  *
  * // When called for the first time for a particular query, you get
  * // an instance of Delta class - this instance contains the results
  * // of your query as well as all the information/state necessary
  * // to perform subsequent queries to get all changes for that resultset
  * $delta = Task::changes( '(objectcategory=person)', ['mail', 'name', 'memberof'], $link );
  * $result = $delta->result;	// Here's where the actual data is
  * // Do something with result...
  *
  * // Now it's time to store the $delta instance someplace safe so we can get
  * // changes for this query at a later time - you should serialise the instance
  * // and store it somewhere - i.e. in a database or on disk
  * file_put_contents( 'my_query_state.txt', serialize( $delta ) );	// Always serialise!
  *
  * // Many moments pass...
  * // In another script, far, far away...
  *
  * // It's time to see which objects have been modified since our last run
  * // Connect to ldap again
  * $link = new Link( 'example.com' );
  * $link->bind( '*****@*****.**', 'SecretPwd' );
  *
  * // Get the previous query state from the file
  * $delta = unserialize( file_get_contents( 'my_query_state.txt' ) );
  * // And get all the objects that have been changed since we last
  * // run the changes method, but this time we only pass in
  * // the instance of Delta class - it contains all the information
  * // about our previous query so we don't have to configure it again
  * $delta = Task::changes( $delta, $link );
  * $result = $delta->result;	// Changed objects are here again!
  *
  * // Notice that now we have a new instance of the Delta class in the
  * // $class variable - reflecting the fact that we just ran the query again
  *
  * // And so the story continues on and on...
  * </code>
  *
  * <h2>Things you should know</h2>
  * <ul>
  * <li>You must always connect to the same domain controller for a particular query,
  * otherwise you will receive the full resultset on each run</li>
  * <li>To track deleted objects, all returned objects have an <i>isDeleted</i>
  * {@link Attribute} automatically that you can use to check if that object has been deleted</li>
  * <li>You cannot use BaseDN overrides with this feature at this time
  * ( this might be implemented in the future )</li>
  * </ul>
  *
  * @return		Delta		Object containing the state and data of the changes
  *
  * @see			<a href="http://msdn.microsoft.com/en-us/library/ms677627.aspx">MSDN - Polling for changes using usnChanged</a>
  */
 public static function changes()
 {
     $args = func_get_args();
     $link = array_pop($args);
     // Link is always last
     $rootDSE = $link->rootDSE;
     $server = $rootDSE->dnsHostName(0);
     // We will only be able to get a diff when talking to the same server next time
     if ($args[0] instanceof Delta) {
         $last_delta = $args[0];
         $filter = $last_delta->filter;
         $attributes = $last_delta->attributes;
         $boundaryUSN = $last_delta->server == $server ? $last_delta->cookie + 1 : 0;
         // Pull all data if we are dealing with a different server
         // Include deleted objects in the resultset
         $link->show_deleted(true);
         // Also make this control extension critical
     } else {
         $filter = $args[0];
         $attributes = $args[1];
         $boundaryUSN = 0;
     }
     $task = new static(Enums\Operation::OpSearch, $link);
     $task->filter(q::a("(usnChanged>={$boundaryUSN})", $filter))->attributes(array_merge($attributes, ['isDeleted']));
     // Include isDeleted to help identifying deleted objects
     // Run, Forest, run!
     $result = $task->run_paged();
     return new Delta($result, $filter, $attributes, $server, $rootDSE->highestCommittedUSN(0));
 }
Example #4
0
 /**
  * Further customise the Selector by providing additional filter
  *
  * This is very useful if you want to write a generic Selector for all users,
  * but sometimes you only need to get disabled users. So, instead of writing
  * a new Selector for that purpose, you can use the `where()` method to refine
  * the search results.
  *
  * @param		string						A valid ldap filter. This will be added to the main filter using '&' logic
  *
  * @return		ADX\Core\Result|mixed		The Result containing all the matched objects or
  * 											whatever the {@link self::_process_result()} returns
  */
 public function where($filter)
 {
     // Build the search filter
     $query = q::a(static::$filter, $filter);
     // If we already have data for this query, no need to load it from server again
     if ($this->query === $query) {
         return $this->_lookup();
     }
     // Remove the previous resultset and execute the query again
     $this->result = null;
     $this->query = $query;
     return $this->_lookup();
 }
Example #5
0
 /**
  * Get all transfer agents for a particular Exchange server
  *
  * @param		Object|string		The Exchange server for which to return mailbox stores
  *
  * @return		Result|mixed		The Result containing all the matched objects or whatever the {@link self::_process_result()} returns
  */
 public function for_server($exchangeServer = null)
 {
     $serverFilter = $exchangeServer !== null ? q::a(['msExchResponsibleMTAServerBL' => "{$exchangeServer}"]) : null;
     return $this->where($serverFilter);
 }
Example #6
0
 /**
  * Build the local schema from server, using provided {@link Link}
  *
  * This method creates the locally cached schema from all schema objects located in
  * CN=Schema,CN=Configuration ( or similar, depending on domain configuration ).
  * The location of the Schema is taken from the RootDSE's "schemanamingcontext" entry.
  *
  * @param		Link		The Link object to be used to connect to directory server
  *
  * @return		void
  */
 public static function build(Link $adxLink)
 {
     // Define where to store the schema definition
     $schemaDir = ADX_ROOT_PATH . static::$schema_dir;
     // Prepare the schema folder either by cleaning it's contents or by creating it
     file_exists($schemaDir) ? static::flush() : mkdir($schemaDir, 0755);
     $schema_base = $adxLink->rootDSE->schemaNamingContext(0);
     // schemanamingcontext is loaded by default
     // Create the tasks...
     // I have to create them separately because I have two different
     // sets of attributes that I need to have loaded
     $tasks[0] = new Task(Enums\Operation::OpList, $adxLink);
     $tasks[0]->use_pages(500)->base($schema_base)->filter(q::a(['objectclass' => 'attributeschema']))->attributes(static::$attribute_properties);
     $tasks[1] = new Task(Enums\Operation::OpList, $adxLink);
     $tasks[1]->use_pages(500)->base($schema_base)->filter(q::a(['objectclass' => 'classschema']))->attributes(static::$class_properties);
     // And retrieve the schema objects!
     foreach ($tasks as $task) {
         // Do not use the Task::run_paged() method as it will very likely hit the memory execution limit.
         // Instead, mimick that method's functionality and handle the data for each page separately
         do {
             $objects = $task->run();
             if ($objects) {
                 // Loop through the schema objects and save them to a local file, named
                 // after the attribute they represent
                 foreach ($objects as $object) {
                     $filename = $object->ldapDisplayName(0) . ".json";
                     $data = $object->json();
                     file_put_contents($schemaDir . ADX_DS . strtolower($filename), $data);
                 }
             } else {
                 throw new Exception('Maximum number of referrals reached');
             }
         } while (!$task->complete);
     }
     // Generate a lockfile to identify the fact that the Schema is present
     file_put_contents($schemaDir . ADX_DS . '.lockfile', time());
 }