diff --git a/app/Console/Commands/LdapSync.php b/app/Console/Commands/LdapSync.php index 45a9bd44a6..1eae7dda9d 100755 --- a/app/Console/Commands/LdapSync.php +++ b/app/Console/Commands/LdapSync.php @@ -91,7 +91,7 @@ class LdapSync extends Command } /* Determine which location to assign users to by default. */ - $location = null; // FIXME - this would be better called "$default_location", which is more explicit about its purpose + $location = null; // TODO - this would be better called "$default_location", which is more explicit about its purpose if ($this->option('location') != '') { $location = Location::where('name', '=', $this->option('location'))->first(); @@ -133,7 +133,7 @@ class LdapSync extends Command foreach ($ldap_ou_locations as $ldap_loc) { try { $location_users = Ldap::findLdapUsers($ldap_loc['ldap_ou']); - } catch (\Exception $e) { // FIXME: this is stolen from line 77 or so above + } catch (\Exception $e) { // TODO: this is stolen from line 77 or so above if ($this->option('json_summary')) { $json_summary = ['error' => true, 'error_message' => trans('admin/users/message.error.ldap_could_not_search').' Location: '.$ldap_loc['name'].' (ID: '.$ldap_loc['id'].') cannot connect to "'.$ldap_loc['ldap_ou'].'" - '.$e->getMessage(), 'summary' => []]; $this->info(json_encode($json_summary)); diff --git a/app/Console/Commands/LdapSyncNg.php b/app/Console/Commands/LdapSyncNg.php deleted file mode 100644 index b271c6c10c..0000000000 --- a/app/Console/Commands/LdapSyncNg.php +++ /dev/null @@ -1,398 +0,0 @@ - - * - * @since 5.0.0 - */ -class LdapSyncNg extends Command -{ - /** - * The name and signature of the console command. - * - * @var string - */ - protected $signature = 'snipeit:ldap-sync-ng - {--location= : A location name } - {--location_id= : A location id} - {--base_dn= : A diffrent base DN to use } - {--summary : Print summary } - {--json_summary : Print summary in json format } - {--dryrun : Run the sync process but don\'t update the database}'; - - /** - * The console command description. - * - * @var string - */ - protected $description = 'Command line LDAP/AD sync'; - - /** - * An LdapAd instance. - * - * @var \App\Models\LdapAd - */ - private $ldap; - - /** - * LDAP settings collection. - * - * @var \Illuminate\Support\Collection - */ - private $settings = null; - - /** - * A default location collection. - * - * @var \Illuminate\Support\Collection - */ - private $defaultLocation = null; - - /** - * Mapped locations collection. - * - * @var \Illuminate\Support\Collection - */ - private $mappedLocations = null; - - /** - * The summary collection. - * - * @var \Illuminate\Support\Collection - */ - private $summary; - - /** - * Is dry-run? - * - * @var bool - */ - private $dryrun = false; - - /** - * Show users to be imported. - * - * @var array - */ - private $userlist = []; - - /** - * Create a new command instance. - */ - public function __construct(LdapAd $ldap) - { - parent::__construct(); - $this->ldap = $ldap; - $this->settings = $this->ldap->ldapSettings; - $this->summary = collect(); - } - - /** - * Execute the console command. - * - * @return mixed - */ - public function handle() - { - $dispatcher = \Adldap\Adldap::getEventDispatcher(); - - // Listen for all model events. - $dispatcher->listen('Adldap\Models\Events\*', function ($eventName, array $data) { - echo $eventName; // Returns 'Adldap\Models\Events\Updating' - var_dump($data); // Returns [0] => (object) Adldap\Models\Events\Updating; - \Log::debug('Event: '.$eventName.' data - '.print_r($data, true)); - }); - $dispatcher->listen('Adldap\Auth\Events\*', function ($eventName, array $data) { - echo $eventName; // Returns 'Adldap\Models\Events\Updating' - var_dump($data); // Returns [0] => (object) Adldap\Models\Events\Updating; - \Log::debug('Event: '.$eventName.' data - '.print_r($data, true)); - }); - - ini_set('max_execution_time', env('LDAP_TIME_LIM', '600')); //600 seconds = 10 minutes - ini_set('memory_limit', '500M'); - $old_error_reporting = error_reporting(); // grab old error_reporting .ini setting, for later re-enablement - error_reporting($old_error_reporting & ~E_DEPRECATED); // disable deprecation warnings, for LDAP in PHP 7.4 (and greater) - - if ($this->option('dryrun')) { - $this->dryrun = true; - } - $this->checkIfLdapIsEnabled(); - $this->checkLdapConnection(); - $this->setBaseDn(); - $this->getUserDefaultLocation(); - /* - * Use the default location if set, this is needed for the LDAP users sync page - */ - if (! $this->option('base_dn') && null == $this->defaultLocation) { - $this->getMappedLocations(); - } - $this->processLdapUsers(); - // Print table of users - if ($this->dryrun) { - $this->info('The following users will be synced!'); - $headers = ['First Name', 'Last Name', 'Username', 'Email', 'Employee #', 'Location Id', 'Status']; - $this->table($headers, $this->summary->toArray()); - } - - error_reporting($old_error_reporting); // re-enable deprecation warnings. - - return $this->getSummary(); - } - - /** - * Generate the LDAP sync summary. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return string - */ - private function getSummary(): string - { - if ($this->option('summary') && null === $this->dryrun) { - $this->summary->each(function ($item) { - $this->info('USER: '.$item['note']); - - if ('ERROR' === $item['status']) { - $this->error('ERROR: '.$item['note']); - } - }); - } elseif ($this->option('json_summary')) { - $json_summary = [ - 'error' => false, - 'error_message' => '', - 'summary' => $this->summary->toArray(), - ]; - $this->info(json_encode($json_summary)); - } - - return ''; - } - - /** - * Create a new user or update an existing user. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param \Adldap\Models\User $snipeUser - */ - private function updateCreateUser(AdldapUser $snipeUser): void - { - $user = $this->ldap->processUser($snipeUser, $this->defaultLocation, $this->mappedLocations); - $summary = [ - 'firstname' => $user->first_name, - 'lastname' => $user->last_name, - 'username' => $user->username, - 'employee_number' => $user->employee_num, - 'email' => $user->email, - 'location_id' => $user->location_id, - ]; - // Only update the database if is not a dry run - if (! $this->dryrun) { - if ($user->isDirty()) { //if nothing on the user changed, don't bother trying to save anything nor put anything in the summary - if ($user->save()) { - $summary['note'] = ($user->wasRecentlyCreated ? 'CREATED' : 'UPDATED'); - $summary['status'] = 'SUCCESS'; - } else { - $errors = ''; - foreach ($user->getErrors()->getMessages() as $error) { - $errors .= implode(', ', $error); - } - $summary['note'] = $snipeUser->getDN().' was not imported. REASON: '.$errors; - $summary['status'] = 'ERROR'; - } - } else { - $summary = null; - } - } - - // $summary['note'] = ($user->getOriginal('username') ? 'UPDATED' : 'CREATED'); // this seems, kinda, like, superfluous, relative to the $summary['note'] thing above, yeah? - if ($summary) { //if the $user wasn't dirty, $summary was set to null so that we will skip the following push() - $this->summary->push($summary); - } - } - - /** - * Process the users to update / create. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function processLdapUsers(): void - { - try { - \Log::debug('CAL:LING GET LDAP SUSERS'); - $ldapUsers = $this->ldap->getLdapUsers(); - \Log::debug('END CALLING GET LDAP USERS'); - } catch (Exception $e) { - $this->outputError($e); - exit($e->getMessage()); - } - - if (0 == $ldapUsers->count()) { - $msg = 'ERROR: No users found!'; - Log::error($msg); - if ($this->dryrun) { - $this->error($msg); - } - exit($msg); - } - - // Process each individual users - foreach ($ldapUsers->getResults() as $user) { // AdLdap2's paginate() method is weird, it gets *everything* and ->getResults() returns *everything* - $this->updateCreateUser($user); - } - } - - /** - * Get the mapped locations if a base_dn is provided. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function getMappedLocations() - { - $ldapOuLocation = Location::where('ldap_ou', '!=', '')->select(['id', 'ldap_ou'])->get(); - $locations = $ldapOuLocation->sortBy(function ($ou, $key) { - return strlen($ou->ldap_ou); - }); - if ($locations->count() > 0) { - $msg = 'Some locations have special OUs set. Locations will be automatically set for users in those OUs.'; - LOG::debug($msg); - if ($this->dryrun) { - $this->info($msg); - } - - $this->mappedLocations = $locations->pluck('ldap_ou', 'id'); // TODO: this seems ok-ish, but the key-> value is going location_id -> OU name, and the primary action here is the opposite of that - going from OU's to location ID's. - } - } - - /** - * Set the base dn if supplied. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function setBaseDn(): void - { - if ($this->option('base_dn')) { - $this->ldap->baseDn = $this->option('base_dn'); - $msg = sprintf('Importing users from specified base DN: "%s"', $this->ldap->baseDn); - LOG::debug($msg); - if ($this->dryrun) { - $this->info($msg); - } - } - } - - /** - * Get a default location id for imported users. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function getUserDefaultLocation(): void - { - $location = $this->option('location_id') ?? $this->option('location'); - if ($location) { - $userLocation = Location::where('name', '=', $location) - ->orWhere('id', '=', intval($location)) - ->select(['name', 'id']) - ->first(); - if ($userLocation) { - $msg = 'Importing users with default location: '.$userLocation->name.' ('.$userLocation->id.')'; - LOG::debug($msg); - - if ($this->dryrun) { - $this->info($msg); - } - - $this->defaultLocation = collect([ - $userLocation->id => $userLocation->name, - ]); - } else { - $msg = 'The supplied location is invalid!'; - LOG::error($msg); - if ($this->dryrun) { - $this->error($msg); - } - exit(0); - } - } - } - - /** - * Check if LDAP intergration is enabled. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function checkIfLdapIsEnabled(): void - { - if (false === $this->settings['ldap_enabled']) { - $msg = 'LDAP intergration is not enabled. Exiting sync process.'; - $this->info($msg); - Log::info($msg); - exit(0); - } - } - - /** - * Check to make sure we can access the server. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function checkLdapConnection(): void - { - try { - $this->ldap->testLdapAdUserConnection(); - $this->ldap->testLdapAdBindConnection(); - } catch (Exception $e) { - $this->outputError($e); - exit(0); - } - } - - /** - * Output the json summary to the screen if enabled. - * - * @param Exception $error - */ - private function outputError($error): void - { - if ($this->option('json_summary')) { - $json_summary = [ - 'error' => true, - 'error_message' => $error->getMessage(), - 'summary' => [], - ]; - $this->info(json_encode($json_summary)); - } - $this->error($error->getMessage()); - LOG::error($error); - } -} diff --git a/app/Http/Controllers/Api/SettingsController.php b/app/Http/Controllers/Api/SettingsController.php index c821253e19..2c4f37bcb0 100644 --- a/app/Http/Controllers/Api/SettingsController.php +++ b/app/Http/Controllers/Api/SettingsController.php @@ -2,15 +2,15 @@ namespace App\Http\Controllers\Api; +use Illuminate\Http\Request; use App\Http\Controllers\Controller; -use App\Http\Transformers\LoginAttemptsTransformer; use App\Models\Ldap; use App\Models\Setting; +use Mail; +use App\Notifications\SlackTest; use App\Notifications\MailTest; -use App\Services\LdapAd; use GuzzleHttp\Client; use Illuminate\Http\JsonResponse; -use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; @@ -22,105 +22,69 @@ use App\Http\Requests\SlackSettingsRequest; class SettingsController extends Controller { - /** - * Test the ldap settings - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param App\Models\LdapAd $ldap - * - * @return \Illuminate\Http\JsonResponse - */ - public function ldapAdSettingsTest(LdapAd $ldap): JsonResponse - { - if (! $ldap->init()) { - Log::info('LDAP is not enabled so we cannot test.'); + + public function ldaptest() + { + $settings = Setting::getSettings(); + + if ($settings->ldap_enabled!='1') { + \Log::debug('LDAP is not enabled cannot test.'); return response()->json(['message' => 'LDAP is not enabled, cannot test.'], 400); } - // The connect, bind and resulting users message - $message = []; + \Log::debug('Preparing to test LDAP connection'); - // This is all kinda fucked right now. The connection test doesn't actually do what you think, - // // and the way we parse the errors - // on the JS side is horrible. - Log::info('Preparing to test LDAP user login'); - // Test user can connect to the LDAP server + $message = []; //where we collect together test messages try { - $ldap->testLdapAdUserConnection(); - $message['login'] = [ - 'message' => 'Successfully connected to LDAP server.', - ]; - } catch (\Exception $ex) { - \Log::debug('Connection to LDAP server '.Setting::getSettings()->ldap_server.' failed. Please check your LDAP settings and try again. Server Responded with error: '.$ex->getMessage()); - - return response()->json( - ['message' => 'Connection to LDAP server '.Setting::getSettings()->ldap_server." failed. Verify that the LDAP hostname is entered correctly and that it can be reached from this web server. \n\nServer Responded with error: ".$ex->getMessage(), - - ], 400); - } - - Log::info('Preparing to test LDAP bind connection'); - // Test user can bind to the LDAP server - try { - Log::info('Testing Bind'); - $ldap->testLdapAdBindConnection(); - $message['bind'] = [ - 'message' => 'Successfully bound to LDAP server.', - ]; - } catch (\Exception $ex) { - Log::info('LDAP Bind failed'); - - return response()->json(['message' => 'Connection to LDAP successful, but we were unable to Bind the LDAP user '.Setting::getSettings()->ldap_uname.". Verify your that your LDAP Bind username and password are correct. \n\nServer Responded with error: ".$ex->getMessage(), - ], 400); - } - - - Log::info('Preparing to get sample user set from LDAP directory'); - // Get a sample of 10 users so user can verify the data is correct - $settings = Setting::getSettings(); - try { - Log::info('Testing LDAP sync'); - error_reporting(E_ALL & ~E_DEPRECATED); // workaround for php7.4, which deprecates ldap_control_paged_result - // $users = $ldap->testUserImportSync(); // from AdLdap2 from v5, disabling and falling back to v4's sync code - $users = collect(Ldap::findLdapUsers())->slice(0, 11)->filter(function ($value, $key) { //choosing ELEVEN because one is going to be the count, which we're about to filter out in the next line - return is_int($key); - })->map(function ($item) use ($settings) { - return (object) [ - 'username' => $item[$settings['ldap_username_field']][0] ?? null, - 'employee_number' => $item[$settings['ldap_emp_num']][0] ?? null, - 'lastname' => $item[$settings['ldap_lname_field']][0] ?? null, - 'firstname' => $item[$settings['ldap_fname_field']][0] ?? null, - 'email' => $item[$settings['ldap_email']][0] ?? null, - ]; - }); - if ($users->count() > 0) { - $message['user_sync'] = [ - 'users' => $users, - ]; - } else { - $message['user_sync'] = [ - 'message' => 'Connection to LDAP was successful, however there were no users returned from your query. You should confirm the Base Bind DN above.', + $connection = Ldap::connectToLdap(); + try { + $message['bind'] = ['message' => 'Successfully bound to LDAP server.']; + \Log::debug('attempting to bind to LDAP for LDAP test'); + Ldap::bindAdminToLdap($connection); + $message['login'] = [ + 'message' => 'Successfully connected to LDAP server.', ]; - return response()->json($message, 400); + $users = collect(Ldap::findLdapUsers(null,10))->filter(function ($value, $key) { + return is_int($key); + })->slice(0, 10)->map(function ($item) use ($settings) { + return (object) [ + 'username' => $item[$settings['ldap_username_field']][0] ?? null, + 'employee_number' => $item[$settings['ldap_emp_num']][0] ?? null, + 'lastname' => $item[$settings['ldap_lname_field']][0] ?? null, + 'firstname' => $item[$settings['ldap_fname_field']][0] ?? null, + 'email' => $item[$settings['ldap_email']][0] ?? null, + ]; + }); + if ($users->count() > 0) { + $message['user_sync'] = [ + 'users' => $users, + ]; + } else { + $message['user_sync'] = [ + 'message' => 'Connection to LDAP was successful, however there were no users returned from your query. You should confirm the Base Bind DN above.', + ]; + + return response()->json($message, 400); + } + + return response()->json($message, 200); + } catch (\Exception $e) { + \Log::debug('Bind failed'); + \Log::debug("Exception was: ".$e->getMessage()); + return response()->json(['message' => $e->getMessage()], 400); + //return response()->json(['message' => $e->getMessage()], 500); } - } catch (\Exception $ex) { - Log::info('LDAP sync failed'); - $message['user_sync'] = [ - 'message' => 'Error getting users from LDAP directory, error: '.$ex->getMessage(), - ]; - - return response()->json($message, 400); + } catch (\Exception $e) { + \Log::debug('Connection failed but we cannot debug it any further on our end.'); + return response()->json(['message' => $e->getMessage()], 500); } - return response()->json($message, 200); + } - public function ldaptestlogin(Request $request, LdapAd $ldap) + public function ldaptestlogin(Request $request) { if (Setting::getSettings()->ldap_enabled != '1') { @@ -129,40 +93,50 @@ class SettingsController extends Controller } - $rules = [ + $rules = array( 'ldaptest_user' => 'required', - 'ldaptest_password' => 'required', - ]; + 'ldaptest_password' => 'required' + ); $validator = Validator::make($request->all(), $rules); if ($validator->fails()) { \Log::debug('LDAP Validation test failed.'); - $validation_errors = implode(' ', $validator->errors()->all()); - + $validation_errors = implode(' ',$validator->errors()->all()); return response()->json(['message' => $validator->errors()->all()], 400); } + \Log::debug('Preparing to test LDAP login'); try { - DB::beginTransaction(); //this was the easiest way to invoke a full test of an LDAP login without adding new users to the DB (which may not be desired) + $connection = Ldap::connectToLdap(); + try { + Ldap::bindAdminToLdap($connection); + \Log::debug('Attempting to bind to LDAP for LDAP test'); + try { + $ldap_user = Ldap::findAndBindUserLdap($request->input('ldaptest_user'), $request->input('ldaptest_password')); + if ($ldap_user) { + \Log::debug('It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'); + return response()->json(['message' => 'It worked! '. $request->input('ldaptest_user').' successfully binded to LDAP.'], 200); + } + return response()->json(['message' => 'Login Failed. '. $request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400); - // $results = $ldap->ldap->auth()->attempt($request->input('ldaptest_username'), $request->input('ldaptest_password'), true); - // can't do this because that's a protected property. + } catch (\Exception $e) { + \Log::debug('LDAP login failed'); + return response()->json(['message' => $e->getMessage()], 400); + } - $results = $ldap->ldapLogin($request->input('ldaptest_user'), $request->input('ldaptest_password')); // this would normally create a user on success (if they didn't already exist), but for the transaction - if ($results) { - return response()->json(['message' => 'It worked! '.$request->input('ldaptest_user').' successfully binded to LDAP.'], 200); - } else { - return response()->json(['message' => 'Login Failed. '.$request->input('ldaptest_user').' did not successfully bind to LDAP.'], 400); + } catch (\Exception $e) { + \Log::debug('Bind failed'); + return response()->json(['message' => $e->getMessage()], 400); + //return response()->json(['message' => $e->getMessage()], 500); } } catch (\Exception $e) { \Log::debug('Connection failed'); - - return response()->json(['message' => $e->getMessage()], 400); - } finally { - DB::rollBack(); // ALWAYS rollback, whether success or failure + return response()->json(['message' => $e->getMessage()], 500); } + + } public function slacktest(SlackSettingsRequest $request) @@ -215,10 +189,9 @@ class SettingsController extends Controller */ public function ajaxTestEmail() { - if (! config('app.lock_passwords')) { + if (!config('app.lock_passwords')) { try { Notification::send(Setting::first(), new MailTest()); - return response()->json(['message' => 'Mail sent to '.config('mail.reply_to.address')], 200); } catch (\Exception $e) { return response()->json(['message' => $e->getMessage()], 500); @@ -291,4 +264,4 @@ class SettingsController extends Controller return (new LoginAttemptsTransformer)->transformLoginAttempts($login_attempt_results, $total); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 2c94cc70b2..65b11e35b9 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Models\Setting; use App\Models\User; -use App\Services\LdapAd; +use App\Models\Ldap; use App\Services\Saml; use Com\Tecnick\Barcode\Barcode; use Google2FA; @@ -39,11 +39,6 @@ class LoginController extends Controller */ protected $redirectTo = '/'; - /** - * @var LdapAd - */ - protected $ldap; - /** * @var Saml */ @@ -52,12 +47,11 @@ class LoginController extends Controller /** * Create a new authentication controller instance. * - * @param LdapAd $ldap * @param Saml $saml * * @return void */ - public function __construct(/*LdapAd $ldap, */ Saml $saml) + public function __construct(Saml $saml) { parent::__construct(); $this->middleware('guest', ['except' => ['logout', 'postTwoFactorAuth', 'getTwoFactorAuth', 'getTwoFactorEnroll']]); @@ -141,13 +135,47 @@ class LoginController extends Controller */ private function loginViaLdap(Request $request): User { - $ldap = \App::make(LdapAd::class); - try { - return $ldap->ldapLogin($request->input('username'), $request->input('password')); - } catch (\Exception $ex) { - LOG::debug('LDAP user login: '.$ex->getMessage()); - throw new \Exception($ex->getMessage()); - } + Log::debug("Binding user to LDAP."); + $ldap_user = Ldap::findAndBindUserLdap($request->input('username'), $request->input('password')); + if (!$ldap_user) { + Log::debug("LDAP user ".$request->input('username')." not found in LDAP or could not bind"); + throw new \Exception("Could not find user in LDAP directory"); + } else { + Log::debug("LDAP user ".$request->input('username')." successfully bound to LDAP"); + } + + // Check if the user already exists in the database and was imported via LDAP + $user = User::where('username', '=', $request->input('username'))->whereNull('deleted_at')->where('ldap_import', '=', 1)->where('activated', '=', '1')->first(); // FIXME - if we get more than one we should fail. and we sure about this ldap_import thing? + Log::debug("Local auth lookup complete"); + + // The user does not exist in the database. Try to get them from LDAP. + // If user does not exist and authenticates successfully with LDAP we + // will create it on the fly and sign in with default permissions + if (!$user) { + Log::debug("Local user ".$request->input('username')." does not exist"); + Log::debug("Creating local user ".$request->input('username')); + + if ($user = Ldap::createUserFromLdap($ldap_user)) { //this handles passwords on its own + Log::debug("Local user created."); + } else { + Log::debug("Could not create local user."); + throw new \Exception("Could not create local user"); + } + // If the user exists and they were imported from LDAP already + } else { + Log::debug("Local user ".$request->input('username')." exists in database. Updating existing user against LDAP."); + + $ldap_attr = Ldap::parseAndMapLdapAttributes($ldap_user); + + if (Setting::getSettings()->ldap_pw_sync=='1') { + $user->password = bcrypt($request->input('password')); + } + $user->email = $ldap_attr['email']; + $user->first_name = $ldap_attr['firstname']; + $user->last_name = $ldap_attr['lastname']; //FIXME (or TODO?) - do we need to map additional fields that we now support? E.g. country, phone, etc. + $user->save(); + } // End if(!user) + return $user; } private function loginViaRemoteUser(Request $request) diff --git a/app/Http/Controllers/Users/LDAPImportController.php b/app/Http/Controllers/Users/LDAPImportController.php index a204581eb6..88a6b207df 100644 --- a/app/Http/Controllers/Users/LDAPImportController.php +++ b/app/Http/Controllers/Users/LDAPImportController.php @@ -4,32 +4,12 @@ namespace App\Http\Controllers\Users; use App\Http\Controllers\Controller; use App\Models\User; -use App\Services\LdapAd; use Illuminate\Http\Request; use Illuminate\Support\Facades\Artisan; // Note that this is awful close to 'Users' the namespace above; be careful class LDAPImportController extends Controller { - /** - * An Ldap instance. - * - * @var LdapAd - */ - protected $ldap; - - /** - * __construct. - * - * @param LdapAd $ldap - */ - public function __construct(LdapAd $ldap) - { - parent::__construct(); - $this->ldap = $ldap; - $this->ldap->init(); - } - - /** + /** * Return view for LDAP import. * * @author Aladin Alaily @@ -43,6 +23,7 @@ class LDAPImportController extends Controller */ public function create() { + // I guess this prolly oughtta... I dunno. Do something? $this->authorize('update', User::class); try { //$this->ldap->connect(); I don't think this actually exists in LdapAd.php, and we don't really 'persist' LDAP connections anyways...right? diff --git a/app/Http/Livewire/LoginForm.php b/app/Http/Livewire/LoginForm.php index 7d10cb78ae..f4fe02f28f 100644 --- a/app/Http/Livewire/LoginForm.php +++ b/app/Http/Livewire/LoginForm.php @@ -38,11 +38,14 @@ class LoginForm extends Component $this->can_submit = false; } - $this->validateOnly($fields); - - $this->can_submit = true; - + $whatever = $this->validateOnly($fields); + //\Log::info(print_r($whatever,true)); + $errors = $this->getErrorBag(); + + $this->can_submit = $this->username !== "" && $this->password !== "" && !$errors->has('username') && !$errors->has('password') ; // wait, what? + + \Log::info("Oy - can we submit yet?!".$this->can_submit); } /** @@ -58,7 +61,7 @@ class LoginForm extends Component public function submitForm() { - $this->can_submit = true; + //$this->can_submit = true; if (auth()->attempt($this->validate())) { return redirect()->intended('/'); diff --git a/app/Models/Ldap.php b/app/Models/Ldap.php index 6b23fd54ec..3861509ebd 100644 --- a/app/Models/Ldap.php +++ b/app/Models/Ldap.php @@ -9,6 +9,22 @@ use Illuminate\Database\Eloquent\Model; use Input; use Log; +/*********************************************** + * TODOS: + * + * First off, we should probably make it so that the main LDAP thing we're using is an *instance* of this class, + * rather than the static methods we use here. We should probably load up that class with its settings, so we + * don't have to explicitly refer to them so often. + * + * Then, we should probably look at embedding some of the logic we use elsewhere into here - the various methods + * should either return a User or false, or other things like that. Don't make the consumers of this class reach + * into its guts. While that conflates this model with the User model, I think having the appropriate logic for + * turning LDAP people into Users ought to belong here, so it's easier on the consumer of this class. + * + * We're probably going to have to eventually make it so that Snipe-IT users can define multiple LDAP servers, + * and having this as a more instance-oriented class will be a step in the right direction. + ***********************************************/ + class Ldap extends Model { /** @@ -87,22 +103,40 @@ class Ldap extends Model if ($ldap_username_field == 'userprincipalname') { $userDn = $username; } else { - // In case they haven't added an AD domain + // TODO - we no longer respect the "add AD Domain to username" checkbox, but it still exists in settings. + // We should probably just eliminate that checkbox to avoid confusion. + // We let it sit in the DB, unused, to facilitate people downgrading (if they decide to). + // Hopefully, in a later release, we can remove it from the settings. + // This logic instead just means that if we're using UPN, we don't append ad_domain, if we aren't, then we do. + // Hopefully that should handle all of our use cases, but if not we can backport our old logic. $userDn = ($settings->ad_domain != '') ? $username.'@'.$settings->ad_domain : $username.'@'.$settings->email_domain; } } - \Log::debug('Attempting to login using distinguished name:'.$userDn); - $filterQuery = $settings->ldap_auth_filter_query.$username; - $filter = Setting::getSettings()->ldap_filter; + $filter = Setting::getSettings()->ldap_filter; //FIXME - this *does* respect the ldap filter, but I believe that AdLdap2 did *not*. $filterQuery = "({$filter}({$filterQuery}))"; \Log::debug('Filter query: '.$filterQuery); if (! $ldapbind = @ldap_bind($connection, $userDn, $password)) { + \Log::debug("Status of binding user: $userDn to directory: (directly!) ".($ldapbind ? "success" : "FAILURE")); if (! $ldapbind = self::bindAdminToLdap($connection)) { - return false; + /* + * TODO PLEASE: + * + * this isn't very clear, so it's important to note: the $ldapbind value is never correctly returned - we never 'return true' from self::bindAdminToLdap() (the function + * just "falls off the end" without ever explictly returning 'true') + * + * but it *does* have an interesting side-effect of checking for the LDAP password being incorrectly encrypted with the wrong APP_KEY, so I'm leaving it in for now. + * + * If it *did* correctly return 'true' on a succesful bind, it would _probably_ allow users to log in with an incorrect password. Which would be horrible! + * + * Let's definitely fix this at the next refactor!!!! + * + */ + \Log::debug("Status of binding Admin user: $userDn to directory instead: ".($ldapbind ? "success" : "FAILURE")); + return false; } } @@ -135,8 +169,6 @@ class Ldap extends Model { $ldap_username = Setting::getSettings()->ldap_uname; - $ldap_username = Setting::getSettings()->ldap_uname; - // Lets return some nicer messages for users who donked their app key, and disable LDAP try { $ldap_pass = \Crypt::decrypt(Setting::getSettings()->ldap_pword); @@ -147,6 +179,11 @@ class Ldap extends Model if (! $ldapbind = @ldap_bind($connection, $ldap_username, $ldap_pass)) { throw new Exception('Could not bind to LDAP: '.ldap_error($connection)); } + // TODO - this just "falls off the end" but the function states that it should return true or false + // unfortunately, one of the use cases for this function is wrong and *needs* for that failure mode to fire + // so I don't want to fix this right now. + // this method MODIFIES STATE on the passed-in $connection and just returns true or false (or, in this case, undefined) + // at the next refactor, this should be appropriately modified to be more consistent. } @@ -233,14 +270,14 @@ class Ldap extends Model * * @author [A. Gianotto] [] * @since [v3.0] - * @param $ldapatttibutes * @param $base_dn + * @param $count * @return array|bool */ - public static function findLdapUsers($base_dn = null) + public static function findLdapUsers($base_dn = null, $count = -1) { $ldapconn = self::connectToLdap(); - $ldap_bind = self::bindAdminToLdap($ldapconn); + self::bindAdminToLdap($ldapconn); // Default to global base DN if nothing else is provided. if (is_null($base_dn)) { $base_dn = Setting::getSettings()->ldap_basedn; @@ -256,40 +293,58 @@ class Ldap extends Model // Perform the search do { - // Paginate (non-critical, if not supported by server) - if (! $ldap_paging = @ldap_control_paged_result($ldapconn, $page_size, false, $cookie)) { - throw new Exception('Problem with your LDAP connection. Try checking the Use TLS setting in Admin > Settings. '); - } - if ($filter != '' && substr($filter, 0, 1) != '(') { // wrap parens around NON-EMPTY filters that DON'T have them, for back-compatibility with AdLdap2-based filters $filter = "($filter)"; } elseif ($filter == '') { $filter = '(cn=*)'; } - $search_results = ldap_search($ldapconn, $base_dn, $filter); - + // HUGE thanks to this article: https://stackoverflow.com/questions/68275972/how-to-get-paged-ldap-queries-in-php-8-and-read-more-than-1000-entries + // which helped me wrap my head around paged results! + \Log::info("ldap conn is: ".$ldapconn." basedn is: $base_dn, filter is: $filter - count is: $count. page size is: $page_size"); //FIXME - remove + // if a $count is set and it's smaller than $page_size then use that as the page size + $ldap_controls = []; + //if($count == -1) { //count is -1 means we have to employ paging to query the entire directory + $ldap_controls = [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'iscritical' => false, 'value' => ['size'=> $count == -1||$count>$page_size ? $page_size : $count, 'cookie' => $cookie]]]; + //} + $search_results = ldap_search($ldapconn, $base_dn, $filter, [], 0, /* $page_size */ -1, -1, LDAP_DEREF_NEVER, $ldap_controls); // TODO - I hate the @, and I hate that we get a full page even if we ask for 10 records. Can we use an ldap_control? + \Log::info("did the search run? I guess so if you got here!"); if (! $search_results) { - return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work. + return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // TODO this is never called in any routed context - only from the Artisan command. So this redirect will never work. } + $errcode = null; + $matcheddn = null; + $errmsg = null; + $referrals = null; + $controls = []; + ldap_parse_result($ldapconn, $search_results, $errcode , $matcheddn , $errmsg , $referrals, $controls); + if (isset($controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'])) { + // You need to pass the cookie from the last call to the next one + $cookie = $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie']; + \Log::debug("okay, at least one more page to go!!!"); + } else { + \Log::debug("okay, we're out of pages - no cookie (or empty cookie) was passed"); + $cookie = ''; + } + // Empty cookie means last page + // Get results from page $results = ldap_get_entries($ldapconn, $search_results); if (! $results) { - return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work. + return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn)); // TODO this is never called in any routed context - only from the Artisan command. So this redirect will never work. } // Add results to result set $global_count += $results['count']; $result_set = array_merge($result_set, $results); + \Log::debug("Total count is: $global_count"); - @ldap_control_paged_result_response($ldapconn, $search_results, $cookie); - } while ($cookie !== null && $cookie != ''); + } while ($cookie !== null && $cookie != '' && ($count == -1 || $global_count < $count)); // some servers don't even have pagination, and some will give you more results than you asked for, so just see if you have enough. // Clean up after search - $result_set['count'] = $global_count; + $result_set['count'] = $global_count; // TODO: I would've figured you could just count the array instead? $results = $result_set; - @ldap_control_paged_result($ldapconn, 0); return $results; } diff --git a/app/Providers/LdapServiceProvider.php b/app/Providers/LdapServiceProvider.php deleted file mode 100644 index 58f93096d3..0000000000 --- a/app/Providers/LdapServiceProvider.php +++ /dev/null @@ -1,39 +0,0 @@ -app->singleton(LdapAd::class, LdapAd::class); - } - - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return [LdapAd::class]; - } -} diff --git a/app/Services/LdapAd.php b/app/Services/LdapAd.php deleted file mode 100644 index 186a2c7a9d..0000000000 --- a/app/Services/LdapAd.php +++ /dev/null @@ -1,572 +0,0 @@ - - * - * @since 5.0.0 - */ -class LdapAd extends LdapAdConfiguration -{ - /* The following is _probably_ the correct logic, but we can't use it because - some users may have been dependent upon the previous behavior, and this - could cause additional access to be available to users they don't want - to allow to log in. - $useraccountcontrol = $results[$i]['useraccountcontrol'][0]; - if( - // based on MS docs at: https://support.microsoft.com/en-us/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties - ($useraccountcontrol & 0x200) && // is a NORMAL_ACCOUNT - !($useraccountcontrol & 0x02) && // *and* _not_ ACCOUNTDISABLE - !($useraccountcontrol & 0x10) // *and* _not_ LOCKOUT - ) { - $user->activated = 1; - } else { - $user->activated = 0; - } */ - const AD_USER_ACCOUNT_CONTROL_FLAGS = [ - '512', // 0x200 NORMAL_ACCOUNT - '544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD - '66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD - '66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD - '262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED - '262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED - '328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD - '328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD - '4260352', // 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH - '1049088', // 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED - '1114624', // 0x110200 NORMAL_ACCOUNT, NOT_DELEGATED, DONT_EXPIRE_PASSWORD - ]; - - /** - * The LDAP results per page. - */ - const PAGE_SIZE = 500; - - /** - * A base dn. - * - * @var string - */ - public $baseDn = null; - - /** - * Adldap instance. - * - * @var \Adldap\Adldap - */ - protected $ldap; - - /** - * Initialize LDAP from user settings - * - * @since 5.0.0 - * - * @return void - */ - public function init() - { - // Already initialized - if ($this->ldap) { - return true; - } - - parent::init(); - if ($this->isLdapEnabled()) { - if ($this->ldapSettings['is_ad'] == 0) { //only for NON-AD setups! - $this->ldapConfig['account_prefix'] = $this->ldapSettings['ldap_auth_filter_query']; - $this->ldapConfig['account_suffix'] = ','.$this->ldapConfig['base_dn']; - } /* - To the point mentioned in ldapLogin(), we might want to add an 'else' clause here that - sets up an 'account_suffix' of '@'.$this->ldapSettings['ad_domain'] *IF* the user has - $this->ldapSettings['ad_append_domain'] enabled. - That code in ldapLogin gets simplified, in exchange for putting all the weirdness here only. - */ - $this->ldap = new Adldap(); - $this->ldap->addProvider($this->ldapConfig); - - return true; - } - - return false; - } - - public function __construct() - { - $this->init(); - } - - /** - * Create a user if they successfully login to the LDAP server. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param string $username - * @param string $password - * - * @return \App\Models\User - * - * @throws Exception - */ - public function ldapLogin(string $username, string $password): User - { - if ($this->ldapSettings['ad_append_domain']) { //if you're using 'userprincipalname', don't check the ad_append_domain checkbox - $login_username = $username.'@'.$this->ldapSettings['ad_domain']; // I feel like could can be solved with the 'suffix' feature? Then this would be easier. - } else { - $login_username = $username; - } - - if ($this->ldapConfig['username'] && $this->ldapConfig['password']) { - $bind_as_user = false; - } else { - $bind_as_user = true; - } - - if (($this->ldap) && ($this->ldap->auth()->attempt($login_username, $password, $bind_as_user) === false)) { - throw new Exception('Unable to validate user credentials!'); - } - - // Should we sync the logged in user - Log::debug('Attempting to find user in LDAP directory'); - $record = $this->ldap->search()->findBy($this->ldapSettings['ldap_username_field'], $username); - - if ($record) { - if ($this->isLdapSync($record)) { - $this->syncUserLdapLogin($record, $password); - } - } else { - throw new Exception('Unable to find user in LDAP directory!'); - } - - $user = User::where('username', $username) - ->whereNull('deleted_at')->where('ldap_import', '=', 1) - ->where('activated', '=', '1')->first(); - /* Above, I could've just done ->firstOrFail() which would've been cleaner, but it would've been miserable to - troubleshoot if it ever came up (giving a really generic and untraceable error message) - */ - if (! $user) { - throw new Exception("User is either deleted, not activated (can't log in), not from LDAP, or can't be found in database"); - } - - return $user; - } - - /** - * Set the user information based on the LDAP settings. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param \Adldap\Models\User $user - * @param null|Collection $defaultLocation - * @param null|Collection $mappedLocations - * - * @return null|\App\Models\User - */ - public function processUser(AdldapUser $user, ?Collection $defaultLocation = null, ?Collection $mappedLocations = null): ?User - { - // Only sync active users <- I think this actually means 'existing', not 'activated/deactivated' - if (! $user) { - return null; - } - $snipeUser = []; - $snipeUser['username'] = $user->{$this->ldapSettings['ldap_username_field']}[0] ?? ''; - $snipeUser['employee_number'] = $user->{$this->ldapSettings['ldap_emp_num']}[0] ?? ''; - $snipeUser['lastname'] = $user->{$this->ldapSettings['ldap_lname_field']}[0] ?? ''; - $snipeUser['firstname'] = $user->{$this->ldapSettings['ldap_fname_field']}[0] ?? ''; - $snipeUser['email'] = $user->{$this->ldapSettings['ldap_email']}[0] ?? ''; - $snipeUser['title'] = $user->getTitle() ?? ''; - $snipeUser['telephonenumber'] = $user->getTelephoneNumber() ?? ''; - - /* - * $locationId being 'null' means we have no per-OU location information, - * but instead of explicitly setting it to null - which would override any admin-generated - * location assignments - we just don't set it at all. For a brand new User, the 'default null' - * on the column will cover us. For an already existing user, this will not override any - * locations that were explicitly chosen by the administrators. - * - * When syncing with a particular 'default location' in mind, those should still be respected - * and it *will* override the administrators previous choices. I think this is a fair compromise. - */ - $locationId = $this->getLocationId($user, $defaultLocation, $mappedLocations); - if ($locationId !== null) { - $snipeUser['location_id'] = $locationId; - } - - $activeStatus = $this->getActiveStatus($user); - if ($activeStatus !== null) { - $snipeUser['activated'] = $activeStatus; - } - - return $this->setUserModel($snipeUser); - } - - /** - * Set the User model information. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param array $userInfo The user info to save to the database - * - * @return \App\Models\User - */ - public function setUserModel(array $userInfo): User - { - // If the username exists, return the user object, otherwise create a new user object - $user = User::firstOrNew([ - 'username' => $userInfo['username'], - ]); - $user->username = $user->username ?? trim($userInfo['username']); - $user->password = $user->password ?? Helper::generateEncyrptedPassword(); - $user->first_name = trim($userInfo['firstname']); - $user->last_name = trim($userInfo['lastname']); - $user->email = trim($userInfo['email']); - $user->employee_num = trim($userInfo['employee_number']); - $user->jobtitle = trim($userInfo['title']); - $user->phone = trim($userInfo['telephonenumber']); - if (array_key_exists('activated', $userInfo)) { - $user->activated = $userInfo['activated']; - } elseif (! $user->exists) { // no 'activated' flag was set or unset, *AND* this user is new - activate by default. - $user->activated = 1; - } - if (array_key_exists('location_id', $userInfo)) { - $user->location_id = $userInfo['location_id']; - } - - // this is a new user - if (! isset($user->id)) { - $user->notes = 'Imported from LDAP'; - } - - $user->ldap_import = 1; - - return $user; - } - - /** - * Sync a user who has logged in by LDAP. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param \Adldap\Models\User $record - * @param string $password - * - * @throws Exception - */ - private function syncUserLdapLogin(AdldapUser $record, string $password): void - { - $user = $this->processUser($record); - - if (is_null($user->last_login)) { - $user->notes = 'Imported on first login from LDAP2'; - } - - if ($this->ldapSettings['ldap_pw_sync']) { - Log::debug('Syncing users password with LDAP directory.'); - $user->password = bcrypt($password); - } - - if (! $user->save()) { - Log::debug('Could not save user. '.$user->getErrors()); - throw new Exception('Could not save user: '.$user->getErrors()); - } - } - - /** - * Check to see if we should sync the user with the LDAP directory. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param \Adldap\Models\User $user - * - * @return bool - */ - private function isLdapSync(AdldapUser $user): bool - { - if (! $this->ldapSettings['ldap_active_flag']) { - return true; // always sync if you didn't define an 'active' flag - } - - if ($user->{$this->ldapSettings['ldap_active_flag']} && // if your LDAP user has the aforementioned flag as an attribute *AND* - count($user->{$this->ldapSettings['ldap_active_flag']}) == 1 && // if that attribute has exactly one value *AND* - strtolower($user->{$this->ldapSettings['ldap_active_flag']}[0]) == 'false') { // that value is the string 'false' (regardless of case), - return false; // then your user is *INACTIVE* - return false - } - // otherwise, return true - return true; - } - - /** - * Set the active status of the user. - * Returns 0 or 1 if the user is deactivated or activated - * or returns null if we just don't know - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param \Adldap\Models\User $user - * - * @return int (or null) - */ - private function getActiveStatus(AdldapUser $user): ?int - { - /* - * Check to see if we are connected to an AD server - * if so, check the Active Directory User Account Control Flags - * If the admin has set their own 'active flag' - respect that instead - * (this may work to allow AD users to ignore the built-in UAC stuff that AD does) - */ - if ($user->hasAttribute($user->getSchema()->userAccountControl()) && ! $this->ldapSettings['ldap_active_flag']) { - \Log::debug('This is AD - userAccountControl is'.$user->getSchema()->userAccountControl()); - $activeStatus = (in_array($user->getUserAccountControl(), self::AD_USER_ACCOUNT_CONTROL_FLAGS)) ? 1 : 0; - } else { - - //\Log::debug('This looks like LDAP (or an AD where the UAC is disabled)'); - // If there is no activated flag, then we can't make any determination about activated/deactivated - if (false == $this->ldapSettings['ldap_active_flag']) { - \Log::debug('ldap_active_flag is false - no ldap_active_flag is set'); - - return null; - } - - // If there *is* an activated flag, then respect it *only* if it is actually present. If it's not there, ignore it. - if (! $user->hasAttribute($this->ldapSettings['ldap_active_flag'])) { - return null; // 'active' flag is defined, but does not exist on returned user record. So we don't know if they're active or not. - } - - // if $user has the flag *AND* that flag has exactly one value - - if ($user->{$this->ldapSettings['ldap_active_flag']} && count($user->{$this->ldapSettings['ldap_active_flag']}) == 1) { - $active_flag_value = $user->{$this->ldapSettings['ldap_active_flag']}[0]; - - // if the value of that flag is case-insensitively the string 'false' or boolean false - if (strcasecmp($active_flag_value, 'false') == 0 || $active_flag_value === false) { - return 0; // then make them INACTIVE - } else { - return 1; // otherwise active - } - } - - return 1; // fail 'open' (active) if we have the attribute and it's multivalued or empty; that's weird - } - - return $activeStatus; - } - - /** - * Get a default selected location, or a OU mapped location if available. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @param \Adldap\Models\User $user - * @param Collection|null $defaultLocation - * @param Collection|null $mappedLocations - * - * @return null|int - */ - private function getLocationId(AdldapUser $user, ?Collection $defaultLocation, ?Collection $mappedLocations): ?int - { - $locationId = null; - // Set the users default locations, if set - if ($defaultLocation) { - $locationId = $defaultLocation->keys()->first(); - } - - // Check to see if the user is in a mapped location - if ($mappedLocations) { - $location = $mappedLocations->filter(function ($value, $key) use ($user) { - //if ($user->inOu($value)) { // <----- *THIS* seems not to be working, and it seems more 'intelligent' - but it's literally just a strpos() call, and it doesn't work quite right against plain strings - $user_ou = substr($user->getDn(), -strlen($value)); // get the LAST chars of the user's DN, the count of those chars being the length of the thing we're checking against - if (strcasecmp($user_ou, $value) === 0) { // case *IN*sensitive comparision - some people say OU=blah, some say ou=blah. returns 0 when strings are identical (which is a little odd, yeah) - return $key; // WARNING: we are doing a 'filter' - not a regular for-loop. So the answer(s) get "return"ed into the $location array - } - }); - - if ($location->count() > 0) { - $locationId = $location->keys()->first(); // from the returned $location array from the ->filter() method above, we return the first match - there should be only one - } - } - - return $locationId; - } - - /** - * Get the base dn for the query. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return string - */ - private function getBaseDn(): string - { - if (! is_null($this->baseDn)) { - return $this->baseDn; - } - - return $this->ldapSettings['ldap_basedn']; - } - - /** - * Format the ldap filter if needed. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return null|string - */ - private function getFilter(): ?string - { - $filter = $this->ldapSettings['ldap_filter']; - if (! $filter) { - return null; - } - // Add surrounding parentheses as needed - $paren = mb_substr($filter, 0, 1, 'utf-8'); - if ('(' !== $paren) { - return '('.$filter.')'; - } - - return $filter; - } - - /** - * Get the selected fields to return - * This should help with memory on large result sets as we are not returning all fields. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return array - */ - private function getSelectedFields(): array - { - /** @var Schema $schema */ - $schema = new $this->ldapConfig['schema']; - - return array_values(array_filter([ - $this->ldapSettings['ldap_username_field'], - $this->ldapSettings['ldap_fname_field'], - $this->ldapSettings['ldap_lname_field'], - $this->ldapSettings['ldap_email'], - $this->ldapSettings['ldap_emp_num'], - $this->ldapSettings['ldap_active_flag'], - $schema->memberOf(), - $schema->userAccountControl(), - $schema->title(), - $schema->telephone(), - ])); - } - - /** - * Test the bind user connection. - * - * @author Wes Hulette - * @throws \Exception - * @since 5.0.0 - */ - public function testLdapAdBindConnection(): void - { - try { - $this->ldap->search()->ous()->get()->count(); //it's saying this is null? - } catch (Exception $th) { - Log::error($th->getMessage()); - throw new Exception('Unable to search LDAP directory!'); - } - } - - /** - * Test the user can connect to the LDAP server. - * - * @author Wes Hulette - * @throws \Exception - * @since 5.0.0 - */ - public function testLdapAdUserConnection(): void - { - try { - $this->ldap->connect(); - } catch (\Exception $e) { - Log::debug('LDAP ERROR: '.$e->getMessage()); - throw new Exception($e->getMessage()); - } - } - - /** - * Test the LDAP configuration by returning up to 10 users. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return Collection - */ - public function testUserImportSync(): Collection - { - $testUsers = collect($this->getLdapUsers()->getResults())->chunk(10)->first(); - if ($testUsers) { - return $testUsers->map(function ($item) { - return (object) [ - 'username' => $item->{$this->ldapSettings['ldap_username_field']}[0] ?? null, - 'employee_number' => $item->{$this->ldapSettings['ldap_emp_num']}[0] ?? null, - 'lastname' => $item->{$this->ldapSettings['ldap_lname_field']}[0] ?? null, - 'firstname' => $item->{$this->ldapSettings['ldap_fname_field']}[0] ?? null, - 'email' => $item->{$this->ldapSettings['ldap_email']}[0] ?? null, - ]; - }); - } - - return collect(); - } - - /** - * Query the LDAP server to get the users to process and return a page set. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return \Adldap\Query\Paginator - */ - public function getLdapUsers(): Paginator - { - $search = $this->ldap->search()->users()->in($this->getBaseDn()); //this looks wrong; we should instead have a passable parameter that does this, and use this as a 'sane' default, yeah? - - $filter = $this->getFilter(); - if (! is_null($filter)) { - $search = $search->rawFilter($filter); - } - //I think it might be possible to potentially do our own paging here? - - return $search->select($this->getSelectedFields()) - ->paginate(self::PAGE_SIZE); - } -} diff --git a/app/Services/LdapAdConfiguration.php b/app/Services/LdapAdConfiguration.php deleted file mode 100644 index 25f0fba372..0000000000 --- a/app/Services/LdapAdConfiguration.php +++ /dev/null @@ -1,311 +0,0 @@ - - * - * @since 5.0.0 - */ -class LdapAdConfiguration -{ - const LDAP_PORT = 389; - const CONNECTION_TIMEOUT = 5; - const DEFAULT_LDAP_VERSION = 3; - const LDAP_BOOLEAN_SETTINGS = [ - 'ldap_enabled', - 'ldap_server_cert_ignore', - 'ldap_tls', - 'ldap_tls', - 'ldap_pw_sync', - 'is_ad', - 'ad_append_domain', - ]; - - /** - * Ldap Settings. - * - * @var Collection - */ - public $ldapSettings; - - /** - * LDAP Config. - * - * @var array - */ - public $ldapConfig; - - /** - * Initialize LDAP from user settings - * - * @since 5.0.0 - */ - public function init() - { - - // This try/catch is dumb, but is necessary to run initial migrations, since - // this service provider is booted even during migrations. :( - snipe - try { - $this->ldapSettings = $this->getSnipeItLdapSettings(); - if ($this->isLdapEnabled()) { - $this->setSnipeItConfig(); - } - } catch (\Exception $e) { - \Log::debug($e); - $this->ldapSettings = null; - } - } - - /** - * Merge the default Adlap config with the SnipeIT config. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function setSnipeItConfig() - { - $this->ldapConfig = $this->setLdapConnectionConfiguration(); - $this->certificateCheck(); - } - - /** - * Get the LDAP settings from the Settings model. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return \Illuminate\Support\Collection - */ - private function getSnipeItLdapSettings(): Collection - { - $ldapSettings = collect(); - if (Setting::first()) { // during early migration steps, there may be no settings table entry to start with - $ldapSettings = Setting::getLdapSettings() - ->map(function ($item, $key) { - // Trim the items - if (is_string($item)) { - $item = trim($item); - } - // Get the boolean value of the LDAP setting, makes it easier to work with them - if (in_array($key, self::LDAP_BOOLEAN_SETTINGS)) { - return boolval($item); - } - - // Decrypt the admin password - if ('ldap_pword' === $key && ! empty($item)) { - try { - return decrypt($item); - } catch (Exception $e) { - throw new Exception('Your app key has changed! Could not decrypt LDAP password using your current app key, so LDAP authentication has been disabled. Login with a local account, update the LDAP password and re-enable it in Admin > Settings.'); - } - } - - if ($item && 'ldap_server' === $key) { - return collect(parse_url($item)); - } - - return $item; - }); - } - - return $ldapSettings; - } - - /** - * Set the server certificate environment variable. - * - * @author Wes Hulette - * - * @since 5.0.0 - */ - private function certificateCheck(): void - { - // If we are ignoring the SSL cert we need to setup the environment variable - // before we create the connection - if ($this->ldapSettings['ldap_server_cert_ignore']) { - putenv('LDAPTLS_REQCERT=never'); - } - - // If the user specifies where CA Certs are, make sure to use them - if (env('LDAPTLS_CACERT')) { - putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT')); - } - } - - /** - * Set the Adlap2 connection configuration values based on SnipeIT settings. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return array - */ - private function setLdapConnectionConfiguration(): array - { - // Create the configuration array. - $ldap_settings = [ - // Mandatory Configuration Options - 'hosts' => $this->getServerUrlBase(), - 'base_dn' => $this->ldapSettings['ldap_basedn'], - 'username' => $this->ldapSettings['ldap_uname'], - 'password' => $this->ldapSettings['ldap_pword'], - - // Optional Configuration Options - 'schema' => $this->getSchema(), // FIXME - we probably ought not to be using this, right? - 'account_prefix' => '', - 'account_suffix' => '', - 'port' => $this->getPort(), - 'follow_referrals' => false, - 'use_ssl' => $this->isSsl(), - 'use_tls' => $this->ldapSettings['ldap_tls'], - 'version' => $this->ldapSettings['ldap_version'] ?? self::DEFAULT_LDAP_VERSION, - 'timeout' => self::CONNECTION_TIMEOUT, - - // Custom LDAP Options - 'custom_options' => [ - // See: http://php.net/ldap_set_option - // LDAP_OPT_X_TLS_REQUIRE_CERT => LDAP_OPT_X_TLS_HARD, - ], - ]; - - if($this->ldapSettings['ldap_client_tls_cert'] || $this->ldapSettings['ldap_client_tls_key']) { - $ldap_settings['custom_options'] = [ - LDAP_OPT_X_TLS_CERTFILE => Setting::get_client_side_cert_path(), - LDAP_OPT_X_TLS_KEYFILE => Setting::get_client_side_key_path() - ]; - } - return $ldap_settings; - } - - /** - * Get the schema to use for the connection. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return string - */ - private function getSchema(): string //wait, what? This is a little weird, since we have completely separate variables for this; we probably shoulnd't be using any 'schema' at all - { - $schema = \Adldap\Schemas\OpenLDAP::class; - if ($this->ldapSettings['is_ad']) { - $schema = \Adldap\Schemas\ActiveDirectory::class; - } - - return $schema; - } - - /** - * Get the port number from the connection url. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return int - */ - private function getPort(): int - { - $port = $this->getLdapServerData('port'); - if ($port && is_int($port)) { - return $port; - } - - return self::LDAP_PORT; - } - - /** - * Get ldap scheme from url to determin ssl use. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return bool - */ - private function isSsl(): bool - { - $scheme = $this->getLdapServerData('scheme'); - if ($scheme && 'ldaps' === strtolower($scheme)) { - return true; - } - - return false; - } - - /** - * Return the base url to the LDAP server. - * - * @author Wes Hulette - * - * @since 5.0.0 - * - * @return array - */ - private function getServerUrlBase(): array - { - /* if ($this->ldapSettings['is_ad']) { - return collect(explode(',', $this->ldapSettings['ad_domain']))->map(function ($item) { - return trim($item); - })->toArray(); - } */ // <- this was the *original* intent of the PR for AdLdap2, but we've been moving away from having - // two separate fields - one for "ldap_host" and one for "ad_domain" - towards just using "ldap_host" - // ad_domain for us just means "append this domain to your usernames for login, if you click that checkbox" - // that's all, nothing more (I hope). - - $url = $this->getLdapServerData('host'); - - return $url ? [$url] : []; - } - - /** - * Get ldap enabled setting - * - * @author Steffen Buehl - * - * @since 5.0.0 - * - * @return bool - */ - public function isLdapEnabled(): bool - { - return $this->ldapSettings && $this->ldapSettings->get('ldap_enabled'); - } - - /** - * Get parsed ldap server information - * - * @author Steffen Buehl - * - * @since 5.0.0 - * - * @param $key - * @return mixed|null - */ - protected function getLdapServerData($key) - { - if ($this->ldapSettings) { - $ldapServer = $this->ldapSettings->get('ldap_server'); - if ($ldapServer && $ldapServer instanceof Collection) { - return $ldapServer->get($key); - } - } - - return null; - } -} diff --git a/composer.json b/composer.json index 13e785f93f..1db3730274 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ "ext-json": "*", "ext-mbstring": "*", "ext-pdo": "*", - "adldap2/adldap2": "^10.2", "alek13/slack": "^2.0", "bacon/bacon-qr-code": "^2.0", "barryvdh/laravel-debugbar": "^3.6", diff --git a/composer.lock b/composer.lock index dab82a6b51..45b93758f4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,73 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b2c8d40131374f1de592b1e05da0d010", + "content-hash": "4cdd1c1cd704c629b2cee1bee7560207", "packages": [ - { - "name": "adldap2/adldap2", - "version": "v10.3.3", - "source": { - "type": "git", - "url": "https://github.com/Adldap2/Adldap2.git", - "reference": "c2a8f72455d3438377d955fc0f4b9ed836b47463" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Adldap2/Adldap2/zipball/c2a8f72455d3438377d955fc0f4b9ed836b47463", - "reference": "c2a8f72455d3438377d955fc0f4b9ed836b47463", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-ldap": "*", - "illuminate/contracts": "~5.0|~6.0|~7.0|~8.0", - "php": ">=7.0", - "psr/log": "~1.0", - "psr/simple-cache": "~1.0", - "tightenco/collect": "~5.0|~6.0|~7.0|~8.0" - }, - "require-dev": { - "mockery/mockery": "~1.0", - "phpunit/phpunit": "~6.0|~7.0|~8.0" - }, - "suggest": { - "ext-fileinfo": "fileinfo is required when retrieving user encoded thumbnails" - }, - "type": "library", - "autoload": { - "psr-4": { - "Adldap\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Steve Bauman", - "email": "steven_bauman@outlook.com", - "role": "Developer" - } - ], - "description": "A PHP LDAP Package for humans.", - "keywords": [ - "active directory", - "ad", - "adLDAP", - "adldap2", - "directory", - "ldap", - "windows" - ], - "support": { - "docs": "https://github.com/Adldap2/Adldap2/blob/master/readme.md", - "email": "steven_bauman@outlook.com", - "issues": "https://github.com/Adldap2/Adldap2/issues", - "source": "https://github.com/Adldap2/Adldap2" - }, - "time": "2021-08-09T15:22:35+00:00" - }, { "name": "alek13/slack", "version": "2.2.1", @@ -139,22 +74,22 @@ }, { "name": "asm89/stack-cors", - "version": "v2.0.3", + "version": "v2.0.5", "source": { "type": "git", "url": "https://github.com/asm89/stack-cors.git", - "reference": "9cb795bf30988e8c96dd3c40623c48a877bc6714" + "reference": "7a198ec737e926eab15d29368fc6fff66772b0e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/asm89/stack-cors/zipball/9cb795bf30988e8c96dd3c40623c48a877bc6714", - "reference": "9cb795bf30988e8c96dd3c40623c48a877bc6714", + "url": "https://api.github.com/repos/asm89/stack-cors/zipball/7a198ec737e926eab15d29368fc6fff66772b0e2", + "reference": "7a198ec737e926eab15d29368fc6fff66772b0e2", "shasum": "" }, "require": { "php": "^7.0|^8.0", - "symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0", - "symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0" + "symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0|~6.0", + "symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0|~6.0" }, "require-dev": { "phpunit/phpunit": "^6|^7|^8|^9", @@ -189,9 +124,9 @@ ], "support": { "issues": "https://github.com/asm89/stack-cors/issues", - "source": "https://github.com/asm89/stack-cors/tree/v2.0.3" + "source": "https://github.com/asm89/stack-cors/tree/v2.0.5" }, - "time": "2021-03-11T06:42:03+00:00" + "time": "2022-01-03T15:27:13+00:00" }, { "name": "aws/aws-crt-php", @@ -245,16 +180,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.207.1", + "version": "3.208.8", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "3120e8adc7b2b060a7eb4c3c5e2a8c25c0f95a94" + "reference": "1fe99375c5a9012d8f99dbbe59fff8e7131a9703" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3120e8adc7b2b060a7eb4c3c5e2a8c25c0f95a94", - "reference": "3120e8adc7b2b060a7eb4c3c5e2a8c25c0f95a94", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1fe99375c5a9012d8f99dbbe59fff8e7131a9703", + "reference": "1fe99375c5a9012d8f99dbbe59fff8e7131a9703", "shasum": "" }, "require": { @@ -330,9 +265,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.207.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.208.8" }, - "time": "2021-12-01T23:44:02+00:00" + "time": "2022-01-03T19:22:28+00:00" }, { "name": "bacon/bacon-qr-code", @@ -389,16 +324,16 @@ }, { "name": "barryvdh/laravel-debugbar", - "version": "v3.6.4", + "version": "v3.6.5", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-debugbar.git", - "reference": "3c2d678269ba60e178bcd93e36f6a91c36b727f1" + "reference": "ccf109f8755dcc7e58779d1aeb1051b04e0b4bef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/3c2d678269ba60e178bcd93e36f6a91c36b727f1", - "reference": "3c2d678269ba60e178bcd93e36f6a91c36b727f1", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/ccf109f8755dcc7e58779d1aeb1051b04e0b4bef", + "reference": "ccf109f8755dcc7e58779d1aeb1051b04e0b4bef", "shasum": "" }, "require": { @@ -426,7 +361,7 @@ "Barryvdh\\Debugbar\\ServiceProvider" ], "aliases": { - "Debugbar": "Barryvdh\\Debugbar\\Facade" + "Debugbar": "Barryvdh\\Debugbar\\Facades\\Debugbar" } } }, @@ -458,7 +393,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-debugbar/issues", - "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.4" + "source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.6.5" }, "funding": [ { @@ -470,7 +405,7 @@ "type": "github" } ], - "time": "2021-10-21T10:57:31+00:00" + "time": "2021-12-14T14:45:18+00:00" }, { "name": "brick/math", @@ -2097,24 +2032,21 @@ }, { "name": "ezyang/htmlpurifier", - "version": "v4.13.0", + "version": "v4.14.0", "source": { "type": "git", "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" + "reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", - "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/12ab42bd6e742c70c0a52f7b82477fcd44e64b75", + "reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75", "shasum": "" }, "require": { "php": ">=5.2" }, - "require-dev": { - "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" - }, "type": "library", "autoload": { "psr-0": { @@ -2145,9 +2077,9 @@ ], "support": { "issues": "https://github.com/ezyang/htmlpurifier/issues", - "source": "https://github.com/ezyang/htmlpurifier/tree/master" + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.14.0" }, - "time": "2020-06-29T00:56:53+00:00" + "time": "2021-12-25T01:21:49+00:00" }, { "name": "facade/flare-client-php", @@ -2216,16 +2148,16 @@ }, { "name": "facade/ignition", - "version": "2.17.2", + "version": "2.17.4", "source": { "type": "git", "url": "https://github.com/facade/ignition.git", - "reference": "af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2" + "reference": "95c80bd35ee6858e9e1439b2f6a698295eeb2070" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/facade/ignition/zipball/af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2", - "reference": "af3cd70d58ca3ef5189ff0e59efbe5a5c043e2d2", + "url": "https://api.github.com/repos/facade/ignition/zipball/95c80bd35ee6858e9e1439b2f6a698295eeb2070", + "reference": "95c80bd35ee6858e9e1439b2f6a698295eeb2070", "shasum": "" }, "require": { @@ -2290,7 +2222,7 @@ "issues": "https://github.com/facade/ignition/issues", "source": "https://github.com/facade/ignition" }, - "time": "2021-11-29T14:04:22+00:00" + "time": "2021-12-27T15:11:24+00:00" }, { "name": "facade/ignition-contracts", @@ -2533,16 +2465,16 @@ }, { "name": "fruitcake/laravel-cors", - "version": "v2.0.4", + "version": "v2.0.5", "source": { "type": "git", "url": "https://github.com/fruitcake/laravel-cors.git", - "reference": "a8ccedc7ca95189ead0e407c43b530dc17791d6a" + "reference": "3a066e5cac32e2d1cdaacd6b961692778f37b5fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/a8ccedc7ca95189ead0e407c43b530dc17791d6a", - "reference": "a8ccedc7ca95189ead0e407c43b530dc17791d6a", + "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/3a066e5cac32e2d1cdaacd6b961692778f37b5fc", + "reference": "3a066e5cac32e2d1cdaacd6b961692778f37b5fc", "shasum": "" }, "require": { @@ -2550,11 +2482,11 @@ "illuminate/contracts": "^6|^7|^8|^9", "illuminate/support": "^6|^7|^8|^9", "php": ">=7.2", - "symfony/http-foundation": "^4|^5", - "symfony/http-kernel": "^4.3.4|^5" + "symfony/http-foundation": "^4|^5|^6", + "symfony/http-kernel": "^4.3.4|^5|^6" }, "require-dev": { - "laravel/framework": "^6|^7|^8", + "laravel/framework": "^6|^7.24|^8", "orchestra/testbench-dusk": "^4|^5|^6|^7", "phpunit/phpunit": "^6|^7|^8|^9", "squizlabs/php_codesniffer": "^3.5" @@ -2598,15 +2530,19 @@ ], "support": { "issues": "https://github.com/fruitcake/laravel-cors/issues", - "source": "https://github.com/fruitcake/laravel-cors/tree/v2.0.4" + "source": "https://github.com/fruitcake/laravel-cors/tree/v2.0.5" }, "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, { "url": "https://github.com/barryvdh", "type": "github" } ], - "time": "2021-04-26T11:24:25+00:00" + "time": "2022-01-03T14:53:04+00:00" }, { "name": "graham-campbell/result-type", @@ -2672,16 +2608,16 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.4.0", + "version": "7.4.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94" + "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94", - "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ee0a041b1760e6a53d2a39c8c34115adc2af2c79", + "reference": "ee0a041b1760e6a53d2a39c8c34115adc2af2c79", "shasum": "" }, "require": { @@ -2690,7 +2626,7 @@ "guzzlehttp/psr7": "^1.8.3 || ^2.1", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", - "symfony/deprecation-contracts": "^2.2" + "symfony/deprecation-contracts": "^2.2 || ^3.0" }, "provide": { "psr/http-client-implementation": "1.0" @@ -2776,7 +2712,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.4.0" + "source": "https://github.com/guzzle/guzzle/tree/7.4.1" }, "funding": [ { @@ -2792,7 +2728,7 @@ "type": "tidelift" } ], - "time": "2021-10-18T09:52:00+00:00" + "time": "2021-12-06T18:43:05+00:00" }, { "name": "guzzlehttp/promises", @@ -2995,16 +2931,16 @@ }, { "name": "intervention/image", - "version": "2.7.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/Intervention/image.git", - "reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545" + "reference": "744ebba495319501b873a4e48787759c72e3fb8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Intervention/image/zipball/9a8cc99d30415ec0b3f7649e1647d03a55698545", - "reference": "9a8cc99d30415ec0b3f7649e1647d03a55698545", + "url": "https://api.github.com/repos/Intervention/image/zipball/744ebba495319501b873a4e48787759c72e3fb8c", + "reference": "744ebba495319501b873a4e48787759c72e3fb8c", "shasum": "" }, "require": { @@ -3063,7 +2999,7 @@ ], "support": { "issues": "https://github.com/Intervention/image/issues", - "source": "https://github.com/Intervention/image/tree/2.7.0" + "source": "https://github.com/Intervention/image/tree/2.7.1" }, "funding": [ { @@ -3075,7 +3011,7 @@ "type": "github" } ], - "time": "2021-10-03T14:17:12+00:00" + "time": "2021-12-16T16:49:26+00:00" }, { "name": "javiereguiluz/easyslugger", @@ -3113,16 +3049,16 @@ }, { "name": "laravel/framework", - "version": "v8.74.0", + "version": "v8.77.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "004ea195012d5132eca07a176a6e587c6a74815e" + "reference": "994dbac5c6da856c77c81a411cff5b7d31519ca8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/004ea195012d5132eca07a176a6e587c6a74815e", - "reference": "004ea195012d5132eca07a176a6e587c6a74815e", + "url": "https://api.github.com/repos/laravel/framework/zipball/994dbac5c6da856c77c81a411cff5b7d31519ca8", + "reference": "994dbac5c6da856c77c81a411cff5b7d31519ca8", "shasum": "" }, "require": { @@ -3140,7 +3076,7 @@ "opis/closure": "^3.6", "php": "^7.3|^8.0", "psr/container": "^1.0", - "psr/log": "^1.0 || ^2.0", + "psr/log": "^1.0|^2.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^4.2.2", "swiftmailer/swiftmailer": "^6.3", @@ -3281,7 +3217,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2021-11-30T15:26:05+00:00" + "time": "2021-12-21T20:22:29+00:00" }, { "name": "laravel/helpers", @@ -3341,16 +3277,16 @@ }, { "name": "laravel/passport", - "version": "v10.2.0", + "version": "v10.2.2", "source": { "type": "git", "url": "https://github.com/laravel/passport.git", - "reference": "1c69a010930a3ce8db348967d8ad9585be4d7d4d" + "reference": "7981abed1a0979afd4a5a8bec81624b8127a287f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/passport/zipball/1c69a010930a3ce8db348967d8ad9585be4d7d4d", - "reference": "1c69a010930a3ce8db348967d8ad9585be4d7d4d", + "url": "https://api.github.com/repos/laravel/passport/zipball/7981abed1a0979afd4a5a8bec81624b8127a287f", + "reference": "7981abed1a0979afd4a5a8bec81624b8127a287f", "shasum": "" }, "require": { @@ -3414,7 +3350,7 @@ "issues": "https://github.com/laravel/passport/issues", "source": "https://github.com/laravel/passport" }, - "time": "2021-11-02T16:45:51+00:00" + "time": "2021-12-07T16:57:03+00:00" }, { "name": "laravel/serializable-closure", @@ -3538,16 +3474,16 @@ }, { "name": "laravel/tinker", - "version": "v2.6.2", + "version": "v2.6.3", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "c808a7227f97ecfd9219fbf913bad842ea854ddc" + "reference": "a9ddee4761ec8453c584e393b393caff189a3e42" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/c808a7227f97ecfd9219fbf913bad842ea854ddc", - "reference": "c808a7227f97ecfd9219fbf913bad842ea854ddc", + "url": "https://api.github.com/repos/laravel/tinker/zipball/a9ddee4761ec8453c584e393b393caff189a3e42", + "reference": "a9ddee4761ec8453c584e393b393caff189a3e42", "shasum": "" }, "require": { @@ -3600,22 +3536,22 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.6.2" + "source": "https://github.com/laravel/tinker/tree/v2.6.3" }, - "time": "2021-09-28T15:47:34+00:00" + "time": "2021-12-07T16:41:42+00:00" }, { "name": "laravel/ui", - "version": "v3.4.0", + "version": "v3.4.1", "source": { "type": "git", "url": "https://github.com/laravel/ui.git", - "reference": "b3e804559bf3973ecca160a4ae1068e6c7c167c6" + "reference": "9a1e52442dd238647905b98d773d59e438eb9f9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/ui/zipball/b3e804559bf3973ecca160a4ae1068e6c7c167c6", - "reference": "b3e804559bf3973ecca160a4ae1068e6c7c167c6", + "url": "https://api.github.com/repos/laravel/ui/zipball/9a1e52442dd238647905b98d773d59e438eb9f9d", + "reference": "9a1e52442dd238647905b98d773d59e438eb9f9d", "shasum": "" }, "require": { @@ -3661,9 +3597,9 @@ "ui" ], "support": { - "source": "https://github.com/laravel/ui/tree/v3.4.0" + "source": "https://github.com/laravel/ui/tree/v3.4.1" }, - "time": "2021-11-30T16:22:00+00:00" + "time": "2021-12-22T10:40:50+00:00" }, { "name": "laravelcollective/html", @@ -3874,16 +3810,16 @@ }, { "name": "league/commonmark", - "version": "2.0.2", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "2df87709f44b0dd733df86aef0830dce9b1f0f13" + "reference": "17d2b9cb5161a2ea1a8dd30e6991d668e503fb9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2df87709f44b0dd733df86aef0830dce9b1f0f13", - "reference": "2df87709f44b0dd733df86aef0830dce9b1f0f13", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/17d2b9cb5161a2ea1a8dd30e6991d668e503fb9d", + "reference": "17d2b9cb5161a2ea1a8dd30e6991d668e503fb9d", "shasum": "" }, "require": { @@ -3902,11 +3838,11 @@ "ext-json": "*", "github/gfm": "0.29.0", "michelf/php-markdown": "^1.4", - "phpstan/phpstan": "^0.12.88", + "phpstan/phpstan": "^0.12.88 || ^1.0.0", "phpunit/phpunit": "^9.5.5", "scrutinizer/ocular": "^1.8.1", "symfony/finder": "^5.3", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0", "unleashedtech/php-coding-standard": "^3.1", "vimeo/psalm": "^4.7.3" }, @@ -3916,7 +3852,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.1-dev" + "dev-main": "2.2-dev" } }, "autoload": { @@ -3956,10 +3892,6 @@ "source": "https://github.com/thephpleague/commonmark" }, "funding": [ - { - "url": "https://enjoy.gitstore.app/repositories/thephpleague/commonmark", - "type": "custom" - }, { "url": "https://www.colinodell.com/sponsor", "type": "custom" @@ -3972,16 +3904,12 @@ "url": "https://github.com/colinodell", "type": "github" }, - { - "url": "https://www.patreon.com/colinodell", - "type": "patreon" - }, { "url": "https://tidelift.com/funding/github/packagist/league/commonmark", "type": "tidelift" } ], - "time": "2021-08-14T14:06:04+00:00" + "time": "2022-01-02T18:25:06+00:00" }, { "name": "league/config", @@ -4205,16 +4133,16 @@ }, { "name": "league/flysystem", - "version": "1.1.8", + "version": "1.1.9", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "c995bb0c23c58c9813d081f9523c9b7bb496698e" + "reference": "094defdb4a7001845300334e7c1ee2335925ef99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c995bb0c23c58c9813d081f9523c9b7bb496698e", - "reference": "c995bb0c23c58c9813d081f9523c9b7bb496698e", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/094defdb4a7001845300334e7c1ee2335925ef99", + "reference": "094defdb4a7001845300334e7c1ee2335925ef99", "shasum": "" }, "require": { @@ -4287,7 +4215,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/1.1.8" + "source": "https://github.com/thephpleague/flysystem/tree/1.1.9" }, "funding": [ { @@ -4295,7 +4223,7 @@ "type": "other" } ], - "time": "2021-11-28T21:50:23+00:00" + "time": "2021-12-09T09:40:50+00:00" }, { "name": "league/flysystem-aws-s3-v3", @@ -4544,16 +4472,16 @@ }, { "name": "livewire/livewire", - "version": "v2.8.1", + "version": "v2.8.2", "source": { "type": "git", "url": "https://github.com/livewire/livewire.git", - "reference": "0f846a93369109e445f0e5009741b1e19e6fa6f6" + "reference": "f6b1726d1068a5b7315f03dc4e58d5763b928374" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/livewire/livewire/zipball/0f846a93369109e445f0e5009741b1e19e6fa6f6", - "reference": "0f846a93369109e445f0e5009741b1e19e6fa6f6", + "url": "https://api.github.com/repos/livewire/livewire/zipball/f6b1726d1068a5b7315f03dc4e58d5763b928374", + "reference": "f6b1726d1068a5b7315f03dc4e58d5763b928374", "shasum": "" }, "require": { @@ -4604,7 +4532,7 @@ "description": "A front-end framework for Laravel.", "support": { "issues": "https://github.com/livewire/livewire/issues", - "source": "https://github.com/livewire/livewire/tree/v2.8.1" + "source": "https://github.com/livewire/livewire/tree/v2.8.2" }, "funding": [ { @@ -4612,7 +4540,7 @@ "type": "github" } ], - "time": "2021-12-02T01:31:26+00:00" + "time": "2021-12-10T19:37:40+00:00" }, { "name": "maatwebsite/excel", @@ -5261,16 +5189,16 @@ }, { "name": "nesbot/carbon", - "version": "2.54.0", + "version": "2.55.2", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "eed83939f1aed3eee517d03a33f5ec587ac529b5" + "reference": "8c2a18ce3e67c34efc1b29f64fe61304368259a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/eed83939f1aed3eee517d03a33f5ec587ac529b5", - "reference": "eed83939f1aed3eee517d03a33f5ec587ac529b5", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8c2a18ce3e67c34efc1b29f64fe61304368259a2", + "reference": "8c2a18ce3e67c34efc1b29f64fe61304368259a2", "shasum": "" }, "require": { @@ -5278,7 +5206,7 @@ "php": "^7.1.8 || ^8.0", "symfony/polyfill-mbstring": "^1.0", "symfony/polyfill-php80": "^1.16", - "symfony/translation": "^3.4 || ^4.0 || ^5.0" + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" }, "require-dev": { "doctrine/dbal": "^2.0 || ^3.0", @@ -5339,6 +5267,7 @@ "time" ], "support": { + "docs": "https://carbon.nesbot.com/docs", "issues": "https://github.com/briannesbitt/Carbon/issues", "source": "https://github.com/briannesbitt/Carbon" }, @@ -5352,7 +5281,7 @@ "type": "tidelift" } ], - "time": "2021-11-01T21:22:20+00:00" + "time": "2021-12-03T14:59:52+00:00" }, { "name": "nette/schema", @@ -6355,16 +6284,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.8.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28" + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/5455cb38aed4523f99977c4a12ef19da4bfe2a28", - "reference": "5455cb38aed4523f99977c4a12ef19da4bfe2a28", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", "shasum": "" }, "require": { @@ -6372,7 +6301,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^6.5.14 || ^7.0.20 || ^8.5.19 || ^9.5.8" + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" }, "type": "library", "extra": { @@ -6392,11 +6321,13 @@ "authors": [ { "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" }, { "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "Option Type for PHP", @@ -6408,7 +6339,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.8.0" + "source": "https://github.com/schmittjoh/php-option/tree/1.8.1" }, "funding": [ { @@ -6420,7 +6351,7 @@ "type": "tidelift" } ], - "time": "2021-08-28T21:27:29+00:00" + "time": "2021-12-04T23:24:31+00:00" }, { "name": "phpseclib/phpseclib", @@ -6535,16 +6466,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e" + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", - "reference": "d86dfc2e2a3cd366cee475e52c6bb3bbc371aa0e", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", + "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", "shasum": "" }, "require": { @@ -6596,9 +6527,9 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.14.0" + "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" }, - "time": "2021-09-10T09:02:12+00:00" + "time": "2021-12-08T12:19:24+00:00" }, { "name": "pragmarx/google2fa", @@ -8230,23 +8161,23 @@ }, { "name": "symfony/console", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ec3661faca1d110d6c307e124b44f99ac54179e3" + "reference": "a2c6b7ced2eb7799a35375fb9022519282b5405e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ec3661faca1d110d6c307e124b44f99ac54179e3", - "reference": "ec3661faca1d110d6c307e124b44f99ac54179e3", + "url": "https://api.github.com/repos/symfony/console/zipball/a2c6b7ced2eb7799a35375fb9022519282b5405e", + "reference": "a2c6b7ced2eb7799a35375fb9022519282b5405e", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php73": "^1.9", "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2|^3", "symfony/string": "^5.1|^6.0" @@ -8309,7 +8240,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.0" + "source": "https://github.com/symfony/console/tree/v5.4.2" }, "funding": [ { @@ -8325,7 +8256,7 @@ "type": "tidelift" } ], - "time": "2021-11-29T15:30:56+00:00" + "time": "2021-12-20T16:11:12+00:00" }, { "name": "symfony/css-selector", @@ -8395,16 +8326,16 @@ }, { "name": "symfony/debug", - "version": "v4.4.31", + "version": "v4.4.36", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "43ede438d4cb52cd589ae5dc070e9323866ba8e0" + "reference": "346e1507eeb3f566dcc7a116fefaa407ee84691b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/43ede438d4cb52cd589ae5dc070e9323866ba8e0", - "reference": "43ede438d4cb52cd589ae5dc070e9323866ba8e0", + "url": "https://api.github.com/repos/symfony/debug/zipball/346e1507eeb3f566dcc7a116fefaa407ee84691b", + "reference": "346e1507eeb3f566dcc7a116fefaa407ee84691b", "shasum": "" }, "require": { @@ -8443,7 +8374,7 @@ "description": "Provides tools to ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v4.4.31" + "source": "https://github.com/symfony/debug/tree/v4.4.36" }, "funding": [ { @@ -8459,7 +8390,7 @@ "type": "tidelift" } ], - "time": "2021-09-24T13:30:14+00:00" + "time": "2021-11-29T08:40:48+00:00" }, { "name": "symfony/deprecation-contracts", @@ -8530,16 +8461,16 @@ }, { "name": "symfony/error-handler", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "8433fa3145ac78df88b87a4a539118e950828126" + "reference": "e0c0dd0f9d4120a20158fc9aec2367d07d38bc56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/8433fa3145ac78df88b87a4a539118e950828126", - "reference": "8433fa3145ac78df88b87a4a539118e950828126", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/e0c0dd0f9d4120a20158fc9aec2367d07d38bc56", + "reference": "e0c0dd0f9d4120a20158fc9aec2367d07d38bc56", "shasum": "" }, "require": { @@ -8581,7 +8512,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.0" + "source": "https://github.com/symfony/error-handler/tree/v5.4.2" }, "funding": [ { @@ -8597,7 +8528,7 @@ "type": "tidelift" } ], - "time": "2021-11-29T15:30:56+00:00" + "time": "2021-12-19T20:02:00+00:00" }, { "name": "symfony/event-dispatcher", @@ -8765,16 +8696,16 @@ }, { "name": "symfony/finder", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590" + "reference": "e77046c252be48c48a40816187ed527703c8f76c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/d2f29dac98e96a98be467627bd49c2efb1bc2590", - "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590", + "url": "https://api.github.com/repos/symfony/finder/zipball/e77046c252be48c48a40816187ed527703c8f76c", + "reference": "e77046c252be48c48a40816187ed527703c8f76c", "shasum": "" }, "require": { @@ -8808,7 +8739,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.0" + "source": "https://github.com/symfony/finder/tree/v5.4.2" }, "funding": [ { @@ -8824,20 +8755,20 @@ "type": "tidelift" } ], - "time": "2021-11-28T15:25:38+00:00" + "time": "2021-12-15T11:06:13+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5ef86ac7927d2de08dc1e26eb91325f9ccbe6309" + "reference": "ce952af52877eaf3eab5d0c08cc0ea865ed37313" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5ef86ac7927d2de08dc1e26eb91325f9ccbe6309", - "reference": "5ef86ac7927d2de08dc1e26eb91325f9ccbe6309", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce952af52877eaf3eab5d0c08cc0ea865ed37313", + "reference": "ce952af52877eaf3eab5d0c08cc0ea865ed37313", "shasum": "" }, "require": { @@ -8881,7 +8812,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.0" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.2" }, "funding": [ { @@ -8897,20 +8828,20 @@ "type": "tidelift" } ], - "time": "2021-11-28T15:25:38+00:00" + "time": "2021-12-28T17:15:56+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "e012f16688bcb151e965473a70d8ebaa8b1d15ea" + "reference": "35b7e9868953e0d1df84320bb063543369e43ef5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/e012f16688bcb151e965473a70d8ebaa8b1d15ea", - "reference": "e012f16688bcb151e965473a70d8ebaa8b1d15ea", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/35b7e9868953e0d1df84320bb063543369e43ef5", + "reference": "35b7e9868953e0d1df84320bb063543369e43ef5", "shasum": "" }, "require": { @@ -8993,7 +8924,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.0" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.2" }, "funding": [ { @@ -9009,20 +8940,20 @@ "type": "tidelift" } ], - "time": "2021-11-29T16:56:53+00:00" + "time": "2021-12-29T13:20:26+00:00" }, { "name": "symfony/mime", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "d4365000217b67c01acff407573906ff91bcfb34" + "reference": "1bfd938cf9562822c05c4d00e8f92134d3c8e42d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/d4365000217b67c01acff407573906ff91bcfb34", - "reference": "d4365000217b67c01acff407573906ff91bcfb34", + "url": "https://api.github.com/repos/symfony/mime/zipball/1bfd938cf9562822c05c4d00e8f92134d3c8e42d", + "reference": "1bfd938cf9562822c05c4d00e8f92134d3c8e42d", "shasum": "" }, "require": { @@ -9076,7 +9007,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.0" + "source": "https://github.com/symfony/mime/tree/v5.4.2" }, "funding": [ { @@ -9092,7 +9023,7 @@ "type": "tidelift" } ], - "time": "2021-11-23T10:19:22+00:00" + "time": "2021-12-28T17:15:56+00:00" }, { "name": "symfony/polyfill-ctype", @@ -9904,16 +9835,16 @@ }, { "name": "symfony/process", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5be20b3830f726e019162b26223110c8f47cf274" + "reference": "2b3ba8722c4aaf3e88011be5e7f48710088fb5e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5be20b3830f726e019162b26223110c8f47cf274", - "reference": "5be20b3830f726e019162b26223110c8f47cf274", + "url": "https://api.github.com/repos/symfony/process/zipball/2b3ba8722c4aaf3e88011be5e7f48710088fb5e4", + "reference": "2b3ba8722c4aaf3e88011be5e7f48710088fb5e4", "shasum": "" }, "require": { @@ -9946,7 +9877,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.0" + "source": "https://github.com/symfony/process/tree/v5.4.2" }, "funding": [ { @@ -9962,7 +9893,7 @@ "type": "tidelift" } ], - "time": "2021-11-28T15:25:38+00:00" + "time": "2021-12-27T21:01:00+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -10227,16 +10158,16 @@ }, { "name": "symfony/string", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "9ffaaba53c61ba75a3c7a3a779051d1e9ec4fd2d" + "reference": "e6a5d5ecf6589c5247d18e0e74e30b11dfd51a3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/9ffaaba53c61ba75a3c7a3a779051d1e9ec4fd2d", - "reference": "9ffaaba53c61ba75a3c7a3a779051d1e9ec4fd2d", + "url": "https://api.github.com/repos/symfony/string/zipball/e6a5d5ecf6589c5247d18e0e74e30b11dfd51a3d", + "reference": "e6a5d5ecf6589c5247d18e0e74e30b11dfd51a3d", "shasum": "" }, "require": { @@ -10293,7 +10224,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.0" + "source": "https://github.com/symfony/string/tree/v5.4.2" }, "funding": [ { @@ -10309,20 +10240,20 @@ "type": "tidelift" } ], - "time": "2021-11-24T10:02:00+00:00" + "time": "2021-12-16T21:52:00+00:00" }, { "name": "symfony/translation", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "6fe32b10e912a518805bc9eafc2a87145773cf13" + "reference": "ff8bb2107b6a549dc3c5dd9c498dcc82c9c098ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/6fe32b10e912a518805bc9eafc2a87145773cf13", - "reference": "6fe32b10e912a518805bc9eafc2a87145773cf13", + "url": "https://api.github.com/repos/symfony/translation/zipball/ff8bb2107b6a549dc3c5dd9c498dcc82c9c098ca", + "reference": "ff8bb2107b6a549dc3c5dd9c498dcc82c9c098ca", "shasum": "" }, "require": { @@ -10390,7 +10321,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.0" + "source": "https://github.com/symfony/translation/tree/v5.4.2" }, "funding": [ { @@ -10406,7 +10337,7 @@ "type": "tidelift" } ], - "time": "2021-11-29T15:30:56+00:00" + "time": "2021-12-25T19:45:36+00:00" }, { "name": "symfony/translation-contracts", @@ -10488,16 +10419,16 @@ }, { "name": "symfony/var-dumper", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "89ab66eaef230c9cd1992de2e9a1b26652b127b9" + "reference": "1b56c32c3679002b3a42384a580e16e2600f41c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/89ab66eaef230c9cd1992de2e9a1b26652b127b9", - "reference": "89ab66eaef230c9cd1992de2e9a1b26652b127b9", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1b56c32c3679002b3a42384a580e16e2600f41c1", + "reference": "1b56c32c3679002b3a42384a580e16e2600f41c1", "shasum": "" }, "require": { @@ -10557,7 +10488,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.0" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.2" }, "funding": [ { @@ -10573,20 +10504,20 @@ "type": "tidelift" } ], - "time": "2021-11-29T15:30:56+00:00" + "time": "2021-12-29T10:10:35+00:00" }, { "name": "tecnickcom/tc-lib-barcode", - "version": "1.17.7", + "version": "1.17.11", "source": { "type": "git", "url": "https://github.com/tecnickcom/tc-lib-barcode.git", - "reference": "5975807c1cc9d9b50377529f22a4fdb435e75b6a" + "reference": "aca01b1be997404aa14e327f70ef51299423b6c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/5975807c1cc9d9b50377529f22a4fdb435e75b6a", - "reference": "5975807c1cc9d9b50377529f22a4fdb435e75b6a", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-barcode/zipball/aca01b1be997404aa14e327f70ef51299423b6c6", + "reference": "aca01b1be997404aa14e327f70ef51299423b6c6", "shasum": "" }, "require": { @@ -10598,12 +10529,12 @@ "tecnickcom/tc-lib-color": "^1.14" }, "require-dev": { - "pdepend/pdepend": "2.8.0", + "pdepend/pdepend": "2.10.2", "phploc/phploc": "7.0.2 || 6.0.2 || 5.0.0 || 4.0.1 || 3.0.1 || 2.1.5", - "phpmd/phpmd": "2.9.1", - "phpunit/phpunit": "9.5.0 || 8.5.13 || 7.5.20 || 6.5.14 || 5.7.27 || 4.8.36", + "phpmd/phpmd": "2.11.1", + "phpunit/phpunit": "9.5.11 || 8.5.13 || 7.5.20 || 6.5.14 || 5.7.27 || 4.8.36", "sebastian/phpcpd": "6.0.3 || 5.0.2 || 4.1.0 || 3.0.1 || 2.0.4", - "squizlabs/php_codesniffer": "3.5.8 || 2.9.2" + "squizlabs/php_codesniffer": "3.6.2 || 2.9.2" }, "type": "library", "autoload": { @@ -10663,7 +10594,7 @@ ], "support": { "issues": "https://github.com/tecnickcom/tc-lib-barcode/issues", - "source": "https://github.com/tecnickcom/tc-lib-barcode/tree/1.17.7" + "source": "https://github.com/tecnickcom/tc-lib-barcode/tree/1.17.11" }, "funding": [ { @@ -10671,20 +10602,20 @@ "type": "custom" } ], - "time": "2021-11-10T20:55:06+00:00" + "time": "2021-12-31T09:42:39+00:00" }, { "name": "tecnickcom/tc-lib-color", - "version": "1.14.6", + "version": "1.14.10", "source": { "type": "git", "url": "https://github.com/tecnickcom/tc-lib-color.git", - "reference": "83cdb57fd900901c6aa2af8cfd67202518fb69b2" + "reference": "ebe0b169122789e4ed6a78d7acd6cf162329c7e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/83cdb57fd900901c6aa2af8cfd67202518fb69b2", - "reference": "83cdb57fd900901c6aa2af8cfd67202518fb69b2", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-color/zipball/ebe0b169122789e4ed6a78d7acd6cf162329c7e4", + "reference": "ebe0b169122789e4ed6a78d7acd6cf162329c7e4", "shasum": "" }, "require": { @@ -10692,12 +10623,12 @@ "php": ">=5.3" }, "require-dev": { - "pdepend/pdepend": "2.8.0", + "pdepend/pdepend": "2.10.2", "phploc/phploc": "7.0.2 || 6.0.2 || 5.0.0 || 4.0.1 || 3.0.1 || 2.1.5", - "phpmd/phpmd": "2.9.1", - "phpunit/phpunit": "9.5.0 || 8.5.13 || 7.5.20 || 6.5.14 || 5.7.27 || 4.8.36", + "phpmd/phpmd": "2.11.1", + "phpunit/phpunit": "9.5.11 || 8.5.13 || 7.5.20 || 6.5.14 || 5.7.27 || 4.8.36", "sebastian/phpcpd": "6.0.3 || 5.0.2 || 4.1.0 || 3.0.1 || 2.0.4", - "squizlabs/php_codesniffer": "3.5.8 || 2.9.2" + "squizlabs/php_codesniffer": "3.6.2 || 2.9.2" }, "type": "library", "autoload": { @@ -10734,7 +10665,7 @@ ], "support": { "issues": "https://github.com/tecnickcom/tc-lib-color/issues", - "source": "https://github.com/tecnickcom/tc-lib-color/tree/1.14.6" + "source": "https://github.com/tecnickcom/tc-lib-color/tree/1.14.10" }, "funding": [ { @@ -10742,61 +10673,7 @@ "type": "custom" } ], - "time": "2021-02-07T13:13:45+00:00" - }, - { - "name": "tightenco/collect", - "version": "v8.68.0", - "source": { - "type": "git", - "url": "https://github.com/tighten/collect.git", - "reference": "8bb884bdab8088b358074f629d8402b64efce2c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tighten/collect/zipball/8bb884bdab8088b358074f629d8402b64efce2c0", - "reference": "8bb884bdab8088b358074f629d8402b64efce2c0", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0", - "symfony/var-dumper": "^3.4 || ^4.0 || ^5.0" - }, - "require-dev": { - "mockery/mockery": "^1.0", - "nesbot/carbon": "^2.23.0", - "phpunit/phpunit": "^8.3" - }, - "type": "library", - "autoload": { - "files": [ - "src/Collect/Support/helpers.php", - "src/Collect/Support/alias.php" - ], - "psr-4": { - "Tightenco\\Collect\\": "src/Collect" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - } - ], - "description": "Collect - Illuminate Collections as a separate package.", - "keywords": [ - "collection", - "laravel" - ], - "support": { - "issues": "https://github.com/tighten/collect/issues", - "source": "https://github.com/tighten/collect/tree/v8.68.0" - }, - "time": "2021-11-30T18:41:31+00:00" + "time": "2021-12-31T09:40:23+00:00" }, { "name": "tightenco/ziggy", @@ -10866,26 +10743,26 @@ }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.3", + "version": "2.2.4", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "b43b05cf43c1b6d849478965062b6ef73e223bb5" + "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/b43b05cf43c1b6d849478965062b6ef73e223bb5", - "reference": "b43b05cf43c1b6d849478965062b6ef73e223bb5", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/da444caae6aca7a19c0c140f68c6182e337d5b1c", + "reference": "da444caae6aca7a19c0c140f68c6182e337d5b1c", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^5.5 || ^7.0 || ^8.0", - "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0" + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" }, "type": "library", "extra": { @@ -10913,9 +10790,9 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.3" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.4" }, - "time": "2020-07-13T06:12:54+00:00" + "time": "2021-12-08T09:12:39+00:00" }, { "name": "unicodeveloper/laravel-password", @@ -10983,16 +10860,16 @@ }, { "name": "vlucas/phpdotenv", - "version": "v5.4.0", + "version": "v5.4.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "d4394d044ed69a8f244f3445bcedf8a0d7fe2403" + "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/d4394d044ed69a8f244f3445bcedf8a0d7fe2403", - "reference": "d4394d044ed69a8f244f3445bcedf8a0d7fe2403", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/264dce589e7ce37a7ba99cb901eed8249fbec92f", + "reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f", "shasum": "" }, "require": { @@ -11030,11 +10907,13 @@ "authors": [ { "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { "name": "Vance Lucas", - "email": "vance@vancelucas.com" + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" } ], "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", @@ -11045,7 +10924,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.4.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.4.1" }, "funding": [ { @@ -11057,7 +10936,7 @@ "type": "tidelift" } ], - "time": "2021-11-10T01:08:39+00:00" + "time": "2021-12-12T23:22:04+00:00" }, { "name": "voku/portable-ascii", @@ -11249,22 +11128,22 @@ "packages-dev": [ { "name": "fakerphp/faker", - "version": "v1.16.0", + "version": "v1.17.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "271d384d216e5e5c468a6b28feedf95d49f83b35" + "reference": "b85e9d44eae8c52cca7aa0939483611f7232b669" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/271d384d216e5e5c468a6b28feedf95d49f83b35", - "reference": "271d384d216e5e5c468a6b28feedf95d49f83b35", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/b85e9d44eae8c52cca7aa0939483611f7232b669", + "reference": "b85e9d44eae8c52cca7aa0939483611f7232b669", "shasum": "" }, "require": { "php": "^7.1 || ^8.0", "psr/container": "^1.0 || ^2.0", - "symfony/deprecation-contracts": "^2.2" + "symfony/deprecation-contracts": "^2.2 || ^3.0" }, "conflict": { "fzaninotto/faker": "*" @@ -11283,7 +11162,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "v1.16-dev" + "dev-main": "v1.17-dev" } }, "autoload": { @@ -11308,9 +11187,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.16.0" + "source": "https://github.com/FakerPHP/Faker/tree/v1.17.0" }, - "time": "2021-09-06T14:53:37+00:00" + "time": "2021-12-05T17:14:47+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -11860,16 +11739,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.9", + "version": "9.2.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b" + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", - "reference": "f301eb1453c9e7a1bc912ee8b0ea9db22c60223b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687", + "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687", "shasum": "" }, "require": { @@ -11925,7 +11804,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10" }, "funding": [ { @@ -11933,7 +11812,7 @@ "type": "github" } ], - "time": "2021-11-19T15:21:02+00:00" + "time": "2021-12-05T09:12:13+00:00" }, { "name": "phpunit/php-file-iterator", @@ -12238,16 +12117,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.10", + "version": "9.5.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a" + "reference": "2406855036db1102126125537adb1406f7242fdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c814a05837f2edb0d1471d6e3f4ab3501ca3899a", - "reference": "c814a05837f2edb0d1471d6e3f4ab3501ca3899a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2406855036db1102126125537adb1406f7242fdd", + "reference": "2406855036db1102126125537adb1406f7242fdd", "shasum": "" }, "require": { @@ -12325,11 +12204,11 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.10" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.11" }, "funding": [ { - "url": "https://phpunit.de/donate.html", + "url": "https://phpunit.de/sponsors.html", "type": "custom" }, { @@ -12337,7 +12216,7 @@ "type": "github" } ], - "time": "2021-09-25T07:38:51+00:00" + "time": "2021-12-25T07:07:57+00:00" }, { "name": "sebastian/cli-parser", @@ -13025,16 +12904,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.6.1", + "version": "3.6.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "f268ca40d54617c6e06757f83f699775c9b3ff2e" + "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/f268ca40d54617c6e06757f83f699775c9b3ff2e", - "reference": "f268ca40d54617c6e06757f83f699775c9b3ff2e", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5e4e71592f69da17871dba6e80dd51bce74a351a", + "reference": "5e4e71592f69da17871dba6e80dd51bce74a351a", "shasum": "" }, "require": { @@ -13077,20 +12956,20 @@ "source": "https://github.com/squizlabs/PHP_CodeSniffer", "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" }, - "time": "2021-10-11T04:00:11+00:00" + "time": "2021-12-12T21:44:58+00:00" }, { "name": "symfony/dom-crawler", - "version": "v4.4.30", + "version": "v4.4.36", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "4632ae3567746c7e915c33c67a2fb6ab746090c4" + "reference": "42de12bee3b5e594977209bcdf58ec4fef8dde39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/4632ae3567746c7e915c33c67a2fb6ab746090c4", - "reference": "4632ae3567746c7e915c33c67a2fb6ab746090c4", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/42de12bee3b5e594977209bcdf58ec4fef8dde39", + "reference": "42de12bee3b5e594977209bcdf58ec4fef8dde39", "shasum": "" }, "require": { @@ -13135,7 +13014,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v4.4.30" + "source": "https://github.com/symfony/dom-crawler/tree/v4.4.36" }, "funding": [ { @@ -13151,20 +13030,20 @@ "type": "tidelift" } ], - "time": "2021-08-28T15:40:01+00:00" + "time": "2021-12-28T14:48:02+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.0", + "version": "v5.4.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc" + "reference": "b9eb163846a61bb32dfc147f7859e274fab38b58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc", - "reference": "034ccc0994f1ae3f7499fa5b1f2e75d5e7a94efc", + "url": "https://api.github.com/repos/symfony/yaml/zipball/b9eb163846a61bb32dfc147f7859e274fab38b58", + "reference": "b9eb163846a61bb32dfc147f7859e274fab38b58", "shasum": "" }, "require": { @@ -13210,7 +13089,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.0" + "source": "https://github.com/symfony/yaml/tree/v5.4.2" }, "funding": [ { @@ -13226,7 +13105,7 @@ "type": "tidelift" } ], - "time": "2021-11-28T15:25:38+00:00" + "time": "2021-12-16T21:58:21+00:00" }, { "name": "theseer/tokenizer", @@ -13293,5 +13172,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/config/app.php b/config/app.php index e8d1ebae49..ab6d62004a 100755 --- a/config/app.php +++ b/config/app.php @@ -345,7 +345,6 @@ return [ * Custom service provider */ App\Providers\MacroServiceProvider::class, - App\Providers\LdapServiceProvider::class, App\Providers\SamlServiceProvider::class, ], diff --git a/resources/views/livewire/login-form.blade.php b/resources/views/livewire/login-form.blade.php index d7cad82505..6561adc8e1 100644 --- a/resources/views/livewire/login-form.blade.php +++ b/resources/views/livewire/login-form.blade.php @@ -41,7 +41,7 @@ {{ trans('admin/users/table.username') }} - + @error('username') {{ $message }} @@ -53,7 +53,7 @@ {{ trans('admin/users/table.password') }} - + @error('password') {{ $message }} diff --git a/resources/views/settings/ldap.blade.php b/resources/views/settings/ldap.blade.php index e01ad2c86a..e87a432da2 100644 --- a/resources/views/settings/ldap.blade.php +++ b/resources/views/settings/ldap.blade.php @@ -122,7 +122,7 @@ - + {{-- NOTICE - this was a feature for AdLdap2-based LDAP syncing, and is already handled in 'classic' LDAP, so we now hide the checkbox (but haven't deleted the field)
{{ Form::label('ad_append_domain', trans('admin/settings/general.ad_append_domain_label')) }} @@ -136,7 +136,7 @@

{{ trans('general.feature_disabled') }}

@endif
-
+ --}}
diff --git a/routes/api.php b/routes/api.php index 85895ec85e..175d17587c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -702,10 +702,10 @@ Route::group(['prefix' => 'v1', 'middleware' => 'api'], function () { */ Route::group(['middleware'=> ['auth', 'authorize:superuser'], 'prefix' => 'settings'], function () { - Route::post('ldaptest', + Route::get('ldaptest', [ Api\SettingsController::class, - 'ldapAdSettingsTest' + 'ldaptest' ] )->name('api.settings.ldaptest');