diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index b1f1753564..a1a18634cc 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -91,6 +91,7 @@ class RestoreFromBackup extends Command 'storage/private_uploads/users', 'storage/private_uploads/licenses', 'storage/private_uploads/signatures', + 'storage/private_uploads/eula-pdfs', ]; $private_files = [ 'storage/oauth-private.key', diff --git a/composer.json b/composer.json index 020b2f9ca7..2a456999e9 100644 --- a/composer.json +++ b/composer.json @@ -74,12 +74,16 @@ "unicodeveloper/laravel-password": "^1.0", "watson/validating": "^6.1" }, + "suggest": { + "ext-ldap": "*" + }, "require-dev": { "brianium/paratest": "^6.6", "fakerphp/faker": "^1.16", "mockery/mockery": "^1.4", "nunomaduro/larastan": "^1.0", "nunomaduro/phpinsights": "^2.7", + "php-mock/php-mock-phpunit": "^2.8", "phpunit/php-token-stream": "^3.1", "phpunit/phpunit": "^9.0", "squizlabs/php_codesniffer": "^3.5", diff --git a/composer.lock b/composer.lock index 7ca88da10f..3d43426260 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "348f96db24a0f8dfb595ee38b38b34eb", + "content-hash": "f4f3b6b02d044ed3e54cdd509b01c3dc", "packages": [ { "name": "alek13/slack", @@ -7011,16 +7011,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.14", + "version": "3.0.34", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "2f0b7af658cbea265cbb4a791d6c29a6613f98ef" + "reference": "56c79f16a6ae17e42089c06a2144467acc35348a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2f0b7af658cbea265cbb4a791d6c29a6613f98ef", - "reference": "2f0b7af658cbea265cbb4a791d6c29a6613f98ef", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a", + "reference": "56c79f16a6ae17e42089c06a2144467acc35348a", "shasum": "" }, "require": { @@ -7032,6 +7032,7 @@ "phpunit/phpunit": "*" }, "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", @@ -7100,7 +7101,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.14" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.34" }, "funding": [ { @@ -7116,7 +7117,7 @@ "type": "tidelift" } ], - "time": "2022-04-04T05:15:45+00:00" + "time": "2023-11-27T11:13:31+00:00" }, { "name": "phpspec/prophecy", @@ -14100,6 +14101,213 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "php-mock/php-mock", + "version": "2.4.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock.git", + "reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d", + "reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0", + "phpunit/php-text-template": "^1 || ^2 || ^3" + }, + "replace": { + "malkusch/php-mock": "*" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.0 || ^9.0 || ^10.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "phpmock\\": [ + "classes/", + "tests/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock/issues", + "source": "https://github.com/php-mock/php-mock/tree/2.4.1" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2023-06-12T20:48:52+00:00" + }, + { + "name": "php-mock/php-mock-integration", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-integration.git", + "reference": "04f4a8d5442ca457b102b5204673f77323e3edb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/04f4a8d5442ca457b102b5204673f77323e3edb5", + "reference": "04f4a8d5442ca457b102b5204673f77323e3edb5", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "php-mock/php-mock": "^2.4", + "phpunit/php-text-template": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6 || ^7 || ^8 || ^9 || ^10" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\integration\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Integration package for PHP-Mock", + "homepage": "https://github.com/php-mock/php-mock-integration", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock-integration/issues", + "source": "https://github.com/php-mock/php-mock-integration/tree/2.2.1" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2023-02-13T09:51:29+00:00" + }, + { + "name": "php-mock/php-mock-phpunit", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-phpunit.git", + "reference": "56edee85ad3232caa0202f98f2a3c899ab16bdb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/56edee85ad3232caa0202f98f2a3c899ab16bdb7", + "reference": "56edee85ad3232caa0202f98f2a3c899ab16bdb7", + "shasum": "" + }, + "require": { + "php": ">=7", + "php-mock/php-mock-integration": "^2.2.1", + "phpunit/phpunit": "^6 || ^7 || ^8 || ^9 || ^10.0.17" + }, + "require-dev": { + "mockery/mockery": "^1.3.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "phpmock\\phpunit\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock-phpunit", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "phpunit", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock-phpunit/issues", + "source": "https://github.com/php-mock/php-mock-phpunit/tree/2.8.0" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2023-10-30T07:06:12+00:00" + }, { "name": "php-parallel-lint/php-parallel-lint", "version": "v1.3.2", @@ -16600,5 +16808,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/public/css/dist/skins/skin-black-dark.css b/public/css/dist/skins/skin-black-dark.css index 2a32df6c9c..bdab8393c5 100644 Binary files a/public/css/dist/skins/skin-black-dark.css and b/public/css/dist/skins/skin-black-dark.css differ diff --git a/public/css/dist/skins/skin-black-dark.min.css b/public/css/dist/skins/skin-black-dark.min.css index d4bd93ca18..fa7c210124 100644 Binary files a/public/css/dist/skins/skin-black-dark.min.css and b/public/css/dist/skins/skin-black-dark.min.css differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 76e272ab0a..3fbbb10fe3 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -12,7 +12,7 @@ "/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=9f944e8021781af1ce45d27765d1c0c2", "/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=cf6c8c340420724b02d6e787ef9bded5", "/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=7f0eb9e355b36b41c61c3af3b4d41143", - "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=f4d95ad9d0944587549e35b6929b4b04", + "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=6cf460bed48ab738041f60231a3f005a", "/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=1f33ca3d860461c1127ec465ab3ebb6b", "/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=0ed42b67f9b02a74815e885bfd9e3f66", "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f", @@ -37,7 +37,7 @@ "/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f", "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=0ed42b67f9b02a74815e885bfd9e3f66", "/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b", - "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=f4d95ad9d0944587549e35b6929b4b04", + "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=6cf460bed48ab738041f60231a3f005a", "/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=392cc93cfc0be0349bab9697669dd091", "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=4a9e8c5e7b09506fa3e3a3f42849e07f", "/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=fc7adb943668ac69fe4b646625a7571f", diff --git a/resources/assets/less/skins/skin-black-dark.less b/resources/assets/less/skins/skin-black-dark.less index 69a393e80d..6f0a2204b2 100644 --- a/resources/assets/less/skins/skin-black-dark.less +++ b/resources/assets/less/skins/skin-black-dark.less @@ -124,11 +124,11 @@ a { --button-primary: darken(@black, 25%); --button-hover: darken(@black, 30%); --header: @black; /* Use same as Header picker */ - --text-main: #BBB; + --text-main: #fff; --text-sub: #9b9b9b; - --link: #AAA; /* Use same as Header picker, lighten by 70% */ - --visited-link: lighten(@black, 40%); /* Use same as Header picker, lighten by 70% */ - --hover-link: lighten(@black, 45%); /* Use same as Header picker, lighten by 70% */ + --link: #fff; /* Use same as Header picker, lighten by 70% */ + --visited-link: #fff; /* Use same as Header picker, lighten by 70% */ + --hover-link: #949494; /* Use same as Header picker, lighten by 70% */ --nav-link: #FFF; /* Use same as Header picker */ --light-link: #fff; /* Use same as Header picker */ } @@ -193,18 +193,6 @@ h2.task_menu{ color: var(--text-main); } -a:link { - color: var(--link); -} - -a:visited { - color: var(--nav-link); -} - -a:hover { - color: var(--hover-link); -} - .btn-primary.hover { color: var(--nav-link); } @@ -318,8 +306,11 @@ input[type=text], input[type=search] { background-color: var(--back-sub); color: var(--text-main); } +.search-highlight, .search-highlight:hover{ + background-color: var(--back-sub) !important; +} .input-group, .input-group-addon { - background-color: var(--back-sub)!important; + background-color: var(--back-sub); color: var(--text-main); } #licensesTable>tbody>tr>td>nobr>a>i.fa { @@ -363,11 +354,11 @@ input[type=text], input[type=search] { } .select2-container--default .select2-results__option[aria-selected=true], .select2-container--default .select2-results__option[aria-selected=true]:hover { background-color: var(--back-sub); - color: var(--header); + color: var(--nav-link); } .select2-container--default .select2-results__option--highlighted[aria-selected] { - background-color: var(--header); - color: var(--back-main); + background-color: var(--back-sub); + color: var(--visited-link); } .select2-container--default .select2-selection--single .select2-selection__rendered { color: var(--text-main); @@ -426,9 +417,6 @@ a { color: var(--hover-link); text-decoration: underline; } - &:visited { - color: var(--visited-link) - } } .row-striped { @@ -463,4 +451,7 @@ a { } div.container.row-new-striped{ background-color: var(--back-sub); +} +.table > thead > tr > td.danger, .table > tbody > tr > td.danger, .table > tfoot > tr > td.danger, .table > thead > tr > th.danger, .table > tbody > tr > th.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > tbody > tr.danger > td, .table > tfoot > tr.danger > td, .table > thead > tr.danger > th, .table > tbody > tr.danger > th, .table > tfoot > tr.danger > th { + background-color: var(--back-sub); } \ No newline at end of file diff --git a/resources/views/licenses/checkin.blade.php b/resources/views/licenses/checkin.blade.php index 075eaa6206..8eeea6f9c4 100755 --- a/resources/views/licenses/checkin.blade.php +++ b/resources/views/licenses/checkin.blade.php @@ -36,7 +36,7 @@
@can('viewKeys', $licenseSeat->license) diff --git a/resources/views/licenses/checkout.blade.php b/resources/views/licenses/checkout.blade.php index a2672be427..e85c677420 100755 --- a/resources/views/licenses/checkout.blade.php +++ b/resources/views/licenses/checkout.blade.php @@ -43,7 +43,7 @@
@can('viewKeys', $license)
diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php
index 0ed5c93b80..5de2d754fb 100755
--- a/resources/views/users/view.blade.php
+++ b/resources/views/users/view.blade.php
@@ -727,7 +727,7 @@
{{ trans('general.name') }}
- {{ trans('admin/hardware/form.serial') }}
+ {{ trans('admin/licenses/form.license_key') }}
{{ trans('general.purchase_cost') }}
{{ trans('admin/licenses/form.purchase_order') }}
{{ trans('general.order_number') }}
diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php
index 17f8af23d2..30fe8c7017 100644
--- a/tests/Support/Settings.php
+++ b/tests/Support/Settings.php
@@ -3,6 +3,7 @@
namespace Tests\Support;
use App\Models\Setting;
+use Illuminate\Support\Facades\Crypt;
class Settings
{
@@ -67,6 +68,39 @@ class Settings
}
+ public function enableLdap(): Settings
+ {
+ return $this->update([
+ 'ldap_enabled' => 1,
+ 'ldap_server' => 'ldaps://ldap.example.com',
+ 'ldap_uname' => 'fake_username',
+ 'ldap_pword' => Crypt::encrypt("fake_password"),
+ 'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
+ ]);
+ }
+
+ public function enableAnonymousLdap(): Settings
+ {
+ return $this->update([
+ 'ldap_enabled' => 1,
+ 'ldap_server' => 'ldaps://ldap.example.com',
+// 'ldap_uname' => 'fake_username',
+ 'ldap_pword' => Crypt::encrypt("fake_password"),
+ 'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
+ ]);
+ }
+
+ public function enableBadPasswordLdap(): Settings
+ {
+ return $this->update([
+ 'ldap_enabled' => 1,
+ 'ldap_server' => 'ldaps://ldap.example.com',
+ 'ldap_uname' => 'fake_username',
+ 'ldap_pword' => "badly_encrypted_password!",
+ 'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com'
+ ]);
+ }
+
/**
* @param array $attributes Attributes to modify in the application's settings.
*/
diff --git a/tests/Unit/LdapTest.php b/tests/Unit/LdapTest.php
new file mode 100644
index 0000000000..bae4f3ff4c
--- /dev/null
+++ b/tests/Unit/LdapTest.php
@@ -0,0 +1,210 @@
+settings->enableLdap();
+
+ $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
+ $ldap_connect->expects($this->once())->willReturn('hello');
+
+ $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
+ $ldap_set_option->expects($this->exactly(3));
+
+
+ $blah = Ldap::connectToLdap();
+ $this->assertEquals('hello',$blah,"LDAP_connect should return 'hello'");
+ }
+
+ // other test cases - with/without client-side certs?
+ // with/without LDAP version 3?
+ // with/without ignore cert validation?
+ // test (and mock) ldap_start_tls() ?
+
+ public function testBindAdmin()
+ {
+ $this->settings->enableLdap();
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
+ $this->assertNull(Ldap::bindAdminToLdap("dummy"));
+ }
+
+ public function testBindBad()
+ {
+ $this->settings->enableLdap();
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false);
+ $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
+ $this->expectExceptionMessage("Could not bind to LDAP:");
+
+ $this->assertNull(Ldap::bindAdminToLdap("dummy"));
+ }
+ // other test cases - test donked password?
+
+ public function testAnonymousBind()
+ {
+ //todo - would be nice to introspect somehow to make sure the right parameters were passed?
+ $this->settings->enableAnonymousLdap();
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
+ $this->assertNull(Ldap::bindAdminToLdap("dummy"));
+ }
+
+ public function testBadAnonymousBind()
+ {
+ $this->settings->enableAnonymousLdap();
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false);
+ $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
+ $this->expectExceptionMessage("Could not bind to LDAP:");
+
+ $this->assertNull(Ldap::bindAdminToLdap("dummy"));
+ }
+
+ public function testBadEncryptedPassword()
+ {
+ $this->settings->enableBadPasswordLdap();
+
+ $this->expectExceptionMessage("Your app key has changed");
+ $this->assertNull(Ldap::bindAdminToLdap("dummy"));
+ }
+
+ public function testFindAndBind()
+ {
+ $this->settings->enableLdap();
+
+ $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
+ $ldap_connect->expects($this->once())->willReturn('hello');
+
+ $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
+ $ldap_set_option->expects($this->exactly(3));
+
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_first_entry")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_get_attributes")->expects($this->once())->willReturn(
+ [
+ "count" => 1,
+ 0 => [
+ 'sn' => 'Surname',
+ 'firstName' => 'FirstName'
+ ]
+ ]
+ );
+
+ $results = Ldap::findAndBindUserLdap("username","password");
+ $this->assertEqualsCanonicalizing(["count" =>1,0 =>['sn' => 'Surname','firstname' => 'FirstName']],$results);
+ }
+
+ public function testFindAndBindBadPassword()
+ {
+ $this->settings->enableLdap();
+
+ $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
+ $ldap_connect->expects($this->once())->willReturn('hello');
+
+ $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
+ $ldap_set_option->expects($this->exactly(3));
+
+ // note - we return FALSE first, to simulate a bad-bind, then TRUE the second time to simulate a successful admin bind
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->exactly(2))->willReturn(false, true);
+
+// $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception");
+
+
+// $this->expectExceptionMessage("exception");
+ $results = Ldap::findAndBindUserLdap("username","password");
+ $this->assertFalse($results);
+ }
+
+ public function testFindAndBindCannotFindSelf()
+ {
+ $this->settings->enableLdap();
+
+ $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
+ $ldap_connect->expects($this->once())->willReturn('hello');
+
+ $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
+ $ldap_set_option->expects($this->exactly(3));
+
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(false);
+
+ $this->expectExceptionMessage("Could not search LDAP:");
+ $results = Ldap::findAndBindUserLdap("username","password");
+ $this->assertFalse($results);
+ }
+
+ //maybe should do an AD test as well?
+
+ public function testFindLdapUsers()
+ {
+ $this->settings->enableLdap();
+
+ $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
+ $ldap_connect->expects($this->once())->willReturn('hello');
+
+ $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
+ $ldap_set_option->expects($this->exactly(3));
+
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(["stuff"]);
+
+ $this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->once())->willReturn(["count" => 1]);
+
+ $results = Ldap::findLdapUsers();
+
+ $this->assertEqualsCanonicalizing(["count" => 1], $results);
+ }
+
+ public function testFindLdapUsersPaginated()
+ {
+ $this->settings->enableLdap();
+
+ $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect");
+ $ldap_connect->expects($this->once())->willReturn('hello');
+
+ $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option");
+ $ldap_set_option->expects($this->exactly(3));
+
+ $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true);
+
+ $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->exactly(2))->willReturn(["stuff"]);
+
+ $this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->exactly(2))->willReturnCallback(
+ function ($ldapconn, $search_results, $errcode , $matcheddn , $errmsg , $referrals, &$controls) {
+ static $count = 0;
+ if($count == 0) {
+ $count++;
+ $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] = "cookie";
+ return ["count" => 1];
+ } else {
+ $controls = [];
+ return ["count" => 1];
+ }
+
+ }
+ );
+
+ $this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->exactly(2))->willReturn(["count" => 1]);
+
+ $results = Ldap::findLdapUsers();
+
+ $this->assertEqualsCanonicalizing(["count" => 2], $results);
+ }
+
+}