Created
February 9, 2017 21:26
-
-
Save jameskraus/fdffe109fac1d056eb7d2f01530a59f0 to your computer and use it in GitHub Desktop.
Modified Adldap2-Larvel Command
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Console\Commands; | |
use Adldap\Models\Entry; | |
use Adldap\Models\Group; | |
use Illuminate\Console\Command; | |
class ImportGroups extends Command | |
{ | |
use ImportsModels; | |
/** | |
* The name and signature of the console command. | |
* | |
* @var string | |
*/ | |
protected $signature = 'groups:import | |
{group? : The group to import} | |
{--filter= : The filter to use} | |
{--no-membership : Do not import the member<->group relationships} | |
{--log= : Whether or not to log} | |
{--connection= : The connection to use} | |
'; | |
/** | |
* The console command description. | |
* | |
* @var string | |
*/ | |
protected $description = 'Import the Groups from LDAP'; | |
/** | |
* Execute the console command. | |
* | |
* @return mixed | |
*/ | |
public function handle() | |
{ | |
// Retrieve the Adldap instance. | |
$adldap = $this->getAdldap($this->option('connection')); | |
if (!$adldap->getConnection()->isBound()) { | |
// If the connection isn't bound yet, we'll connect to the server manually. | |
$adldap->connect(); | |
} | |
// Generate a new user search. | |
$search = $adldap->search()->groups(); | |
if ($filter = $this->getFilter()) { | |
// If the filter option was given, we'll | |
// insert it into our search query. | |
$search->rawFilter($filter); | |
} | |
if ($group = $this->argument('group')) { | |
$groups = [$search->findOrFail($group)]; | |
$this->info("Found group '{$groups[0]->getCommonName()}'. Importing..."); | |
} else { | |
// Retrieve all users. We'll paginate our search in case we hit | |
// the 1000 record hard limit of active directory. | |
$groups = $search->paginate()->getResults(); | |
$count = count($groups); | |
$this->info("Found {$count} groups(s). Importing..."); | |
} | |
$this->info("\nSuccessfully imported / synchronized {$this->import_groups($groups)} groups(s)."); | |
} | |
public function import_groups(array $groups = []) | |
{ | |
// Entries and models imported | |
$imported_entries_and_models = $this->import($groups, Group::class, \App\Group::class); | |
$should_import_membership = !$this->option('no-membership'); | |
$this->info("\n"); | |
if ($should_import_membership) { | |
foreach ($imported_entries_and_models as ['entry' => $entry, 'model' => $group_model]){ | |
$this->info("Importing members for {$entry->getCommonName()}"); | |
$db_users = $group_model->users->keyBy(function ($u) { | |
return bin2hex($u->guid); | |
})->toArray(); | |
$ldap_users = $entry->getMembers()->keyBy(function ($u) { | |
return bin2hex($u->objectguid[0]); | |
})->toArray(); | |
$db_users_to_remove = array_filter($db_users, function ($user_guid) use ($ldap_users) { | |
return !array_key_exists($user_guid, $ldap_users); | |
}, ARRAY_FILTER_USE_KEY); | |
$ldap_users_to_add = array_filter($ldap_users, function ($user_guid) use ($db_users) { | |
return !array_key_exists($user_guid, $db_users); | |
}, ARRAY_FILTER_USE_KEY); | |
foreach ($ldap_users_to_add as $user){ | |
$user_model = $this->getModelFromAdldap($user, \App\User::class); | |
$this->info("...Connecting {$user_model->name} to {$group_model->name}"); | |
$user_model->groups()->save($group_model); | |
} | |
foreach( $db_users_to_remove as $user ){ | |
$this->info("...Detaching {$user['name']} from {$group_model->name}"); | |
$group_model->users()->detach($user['id']); | |
} | |
// Does all the detaching in one step | |
//$group_model->users()->detach($user_ids_to_remove); | |
} | |
} | |
return count($imported_entries_and_models); | |
} | |
/** | |
* Imports the specified groups and returns the total | |
* number of groups successfully imported. | |
* | |
* @param Entry[] $entries | |
* | |
* @param string $ldap_type Class name for Adldap model | |
* @param string $model_type Class name for eloquent model | |
* @return array | |
*/ | |
public function import(array $entries = [], $ldap_type, $model_type) | |
{ | |
$imported = []; | |
// We need to filter our results to make sure they are | |
// only users. In some cases, Contact models may be | |
// returned due the possibility of the | |
// existing in the same scope. | |
$entries = collect($entries)->filter(function ($entry) use ($ldap_type) { | |
return $entry instanceof $ldap_type; | |
}); | |
$bar = $this->output->createProgressBar(count($entries)); | |
foreach ($entries as $entry) { | |
try { | |
// Import the group and retrieve it's model. | |
$model = $this->getModelFromAdldap($entry, $model_type); | |
// Save the returned model. | |
$this->save($entry, $model); | |
$imported[] = [ | |
'entry' => $entry, | |
'model' => $model | |
]; | |
} catch (\Exception $e) { | |
// Log the unsuccessful import. | |
if ($this->isLogging()) { | |
logger()->error("Unable to import group {$entry->getCommonName()}. {$e->getMessage()}"); | |
} | |
} | |
$bar->advance(); | |
} | |
return $imported; | |
} | |
/** | |
* Returns true / false if the current import is being logged. | |
* | |
* @return bool | |
*/ | |
public function isLogging() | |
{ | |
return $this->option('log') == 'true'; | |
} | |
/** | |
* Returns true / false if users are being deleted if they are disabled in AD. | |
* | |
* @return bool | |
*/ | |
public function isDeleting() | |
{ | |
return $this->option('delete') == 'true'; | |
} | |
/** | |
* Returns the limitation filter for the group query. | |
* | |
* @return string | |
*/ | |
public function getFilter() | |
{ | |
return $this->getLimitationFilter() ?: $this->option('filter'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Console\Commands; | |
use Adldap\Laravel\Facades\Adldap; | |
use Adldap\Models\Entry; | |
use Illuminate\Database\Eloquent\Model; | |
trait ImportsModels | |
{ | |
/** | |
* Returns an existing or new Eloquent user from the specified Adldap user instance. | |
* | |
* @param Entry $entry | |
* @param string $model_class | |
* @return Model | |
* @internal param Entry $entity | |
* | |
*/ | |
protected function getModelFromAdldap(Entry $entry, $model_class) | |
{ | |
$model = $this->findOrCreateModelFromAdldap($entry, $model_class); | |
// Synchronize other active directory attributes on the model. | |
$model = $this->syncModelFromAdldap($entry, $model); | |
return $model; | |
} | |
/** | |
* Returns a new Eloquent user query. | |
* | |
* @param string $key | |
* @param string $value | |
* @param string $model_class | |
* | |
* @return \Illuminate\Database\Eloquent\Builder | |
*/ | |
protected function newEloquentQuery($key, $value, $model_class) | |
{ | |
$model = new $model_class(); | |
if (method_exists($model, 'trashed')) { | |
// If the trashed method exists on our User model, then we must be | |
// using soft deletes. We need to make sure we include these | |
// results so we don't create duplicate user records. | |
$model = $model->withTrashed(); | |
} | |
return $model->where([$key => $value]); | |
} | |
/** | |
* Finds an Eloquent model from the specified Adldap user. | |
* | |
* @param Entry $entry | |
* | |
* @param string $model_class | |
* @return Model | |
*/ | |
protected function findOrCreateModelFromAdldap(Entry $entry, $model_class) | |
{ | |
// Get the model key. | |
$attributes = $this->getGUIDAttribute(); | |
// Get the model key. | |
$key = key($attributes); | |
// Get the guid from the AD model. | |
$guid = $entry->{$attributes[$key]}; | |
// Make sure we retrieve the first guid result if it's an array. | |
$guid = (is_array($guid) ? array_get($guid, 0) : $guid); | |
// Try to find the local database group record. | |
$model = $this->newEloquentQuery($key, $guid, $model_class)->first(); | |
// Create a new model instance of it isn't found. | |
$model = ($model instanceof Model ? $model : new $model_class() ); | |
// Set the guid | |
$model->{$key} = $guid; | |
return $model; | |
} | |
/** | |
* Saves the specified model. | |
* | |
* @param Model $model | |
* | |
* @return bool | |
*/ | |
protected function saveModel(Model $model) | |
{ | |
return $model->save(); | |
} | |
/** | |
* Saves the specified user with its model. | |
* | |
* @param Entry $entry | |
* @param Model $model | |
* | |
* @return bool | |
*/ | |
protected function save(Entry $entry, Model $model) | |
{ | |
$imported = false; | |
if ($this->saveModel($model) && $model->wasRecentlyCreated) { | |
$imported = true; | |
// Log the successful import. | |
if ($this->isLogging()) { | |
logger()->info("Imported {$entry->getObjectClass()} {$entry->getCommonName()}"); | |
} | |
} | |
return $imported; | |
} | |
/** | |
* Fills a models attributes by the specified Users attributes. | |
* | |
* @param Entry $entry | |
* @param Model $model | |
* | |
* @return Model | |
*/ | |
protected function syncModelFromAdldap(Entry $entry, Model $model) | |
{ | |
foreach ($this->getSyncAttributes() as $modelField => $adField) { | |
$value = $this->isAttributeCallback($adField) ? | |
$this->handleAttributeCallback($entry, $adField) : | |
$this->handleAttributeRetrieval($entry, $adField); | |
$model->{$modelField} = $value; | |
} | |
return $model; | |
} | |
/** | |
* Handles retrieving the specified field from the User model. | |
* | |
* @param Entry $entry | |
* @param string $field | |
* | |
* @return string|null | |
*/ | |
protected function handleAttributeRetrieval(Entry $entry, $field) | |
{ | |
// Disabled check | |
//if (false && $field === $this->getSchema()->thumbnail()) { | |
// If the field we're retrieving is the groups thumbnail photo, we need | |
// to retrieve it encoded so we're able to save it to the database. | |
// $value = $entry->getThumbnailEncoded(); | |
//} else { | |
$value = $entry->{$field}; | |
// If the AD Value is an array, we'll | |
// retrieve the first value. | |
$value = (is_array($value) ? array_get($value, 0) : $value); | |
//} | |
return $value; | |
} | |
/** | |
* Handles retrieving the value from an attribute callback. | |
* | |
* @param Entry $entry | |
* @param string $callback | |
* | |
* @return mixed | |
*/ | |
protected function handleAttributeCallback(Entry $entry, $callback) | |
{ | |
// Explode the callback into its class and method. | |
list($class, $method) = explode('@', $callback); | |
// Create the handler. | |
$handler = app($class); | |
// Call the attribute handler method and return the result. | |
return call_user_func_array([$handler, $method], [$entry]); | |
} | |
/** | |
* Returns true / false if the specified string | |
* is a callback for an attribute handler. | |
* | |
* @param string $string | |
* | |
* @return bool | |
*/ | |
protected function isAttributeCallback($string) | |
{ | |
$matches = preg_grep("/(\w)@(\w)/", explode("\n", $string)); | |
return count($matches) > 0; | |
} | |
/** | |
* Returns the root Adldap provider instance. | |
* | |
* @param string $provider | |
* | |
* @return \Adldap\Contracts\Connections\ProviderInterface | |
*/ | |
protected function getAdldap($provider = null) | |
{ | |
$provider = $provider ?: $this->getDefaultConnectionName(); | |
return Adldap::getManager()->get($provider); | |
} | |
/** | |
* Returns Adldap's current attribute schema. | |
* | |
* @return \Adldap\Contracts\Schemas\SchemaInterface | |
*/ | |
protected function getSchema() | |
{ | |
return $this->getAdldap()->getSchema(); | |
} | |
/** | |
* Returns the configured login limitation filter. | |
* | |
* @return string|null | |
*/ | |
protected function getLimitationFilter() | |
{ | |
return config('app.ldap.group.limitation_filter'); | |
} | |
/** | |
* Returns the configured guid attribute for discovering LDAP users. | |
* | |
* @return array | |
*/ | |
protected function getGUIDAttribute() | |
{ | |
return config('app.ldap.group.guidAttribute', ['guid' => $this->getSchema()->objectGuid()]); | |
} | |
/** | |
* Returns the configured sync attributes for filling the | |
* Laravel user model with active directory fields. | |
* | |
* @return array | |
*/ | |
protected function getSyncAttributes() | |
{ | |
return config('app.ldap.group.sync_attributes', ['name' => $this->getSchema()->commonName()]); | |
} | |
/** | |
* Returns the configured default connection name. | |
* | |
* @return mixed | |
*/ | |
protected function getDefaultConnectionName() | |
{ | |
return config('adldap_auth.connection', 'default'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment