diff --git a/app/Models/SCIMUser.php b/app/Models/SCIMUser.php new file mode 100644 index 0000000000..71bd9169ae --- /dev/null +++ b/app/Models/SCIMUser.php @@ -0,0 +1,16 @@ +ignoreWrite()->setRead( + function (&$object) { + return $object->getFullNameAttribute(); + } + ); + + $config['validations'][$core.'emails'] = 'nullable|array'; // emails are not required in Snipe-IT... + $config['validations'][$core.'emails.*.value'] = 'required|email'; // ...but if you give us one, it better be an email address + + $mappings['emails'] = [[ + "value" => AttributeMapping::eloquent("email"), + "display" => null, + "type" => AttributeMapping::constant("work")->ignoreWrite(), + "primary" => AttributeMapping::constant(true)->ignoreWrite() + ]]; + + //active + $config['validations'][$core.'active'] = 'boolean'; + + $mappings['active'] = AttributeMapping::eloquent('activated'); + + //phone + $config['validations'][$core.'phoneNumbers'] = 'nullable|array'; + $config['validations'][$core.'phoneNumbers.*.value'] = 'required'; + + $mappings['phoneNumbers'] = [[ + "value" => AttributeMapping::eloquent("phone"), + "display" => null, + "type" => AttributeMapping::constant("work")->ignoreWrite(), + "primary" => AttributeMapping::constant(true)->ignoreWrite() + ]]; + + //address + $config['validations'][$core.'addresses'] = 'nullable|array'; + $config['validations'][$core.'addresses.*.streetAddress'] = 'required'; + $config['validations'][$core.'addresses.*.locality'] = 'string'; + $config['validations'][$core.'addresses.*.region'] = 'string'; + $config['validations'][$core.'addresses.*.postalCode'] = 'string'; + $config['validations'][$core.'addresses.*.country'] = 'string'; + + $mappings['addresses'] = [[ + 'type' => AttributeMapping::constant("work")->ignoreWrite(), + 'formatted' => AttributeMapping::constant("n/a")->ignoreWrite(), // TODO - is this right? This doesn't look right. + 'streetAddress' => AttributeMapping::eloquent("address"), + 'locality' => AttributeMapping::eloquent("city"), + 'region' => AttributeMapping::eloquent("state"), + 'postalCode' => AttributeMapping::eloquent("zip"), + 'country' => AttributeMapping::eloquent("country"), + 'primary' => AttributeMapping::constant(true)->ignoreWrite() //this isn't in the example? + ]]; + + //title + $config['validations'][$core.'title'] = 'string'; + $mappings['title'] = AttributeMapping::eloquent('jobtitle'); + + //Preferred Language + $config['validations'][$core.'preferredLanguage'] = 'string'; + $mappings['preferredLanguage'] = AttributeMapping::eloquent('locale'); + + /* + more snipe-it attributes I'd like to check out (to map to 'enterprise' maybe?): + - website + - notes? + - remote??? + - location_id ? + - company_id to "organization?" + */ + + $enterprise_namespace = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'; + $ent = $enterprise_namespace.':'; + + // we remove the 'example' namespace and add the Enterprise one + $config['mapping']['schemas'] = AttributeMapping::constant( [$core_namespace, $enterprise_namespace] )->ignoreWrite(); + + $config['validations'][$ent.'employeeNumber'] = 'string'; + $config['validations'][$ent.'department'] = 'string'; + $config['validations'][$ent.'manager'] = 'nullable'; + $config['validations'][$ent.'manager.value'] = 'string'; + + $config['mapping'][$enterprise_namespace] = [ + 'employeeNumber' => AttributeMapping::eloquent('employee_num'), + 'department' =>(new AttributeMapping())->setAdd( // FIXME parent? + function ($value, &$object) { + \Log::error("Department-Add: $value"); //FIXME + $department = Department::where("name", $value)->first(); + if ($department) { + $object->department_id = $department->id; + } + } + )->setReplace( + function ($value, &$object) { + \Log::error("Department-Replace: $value"); //FIXME + $department = Department::where("name", $value)->first(); + if ($department) { + $object->department_id = $department->id; + } + } + )->setRead( + function (&$object) { + \Log::error("Weird department reader firing..."); //FIXME + return $object->department ? $object->department->name : null; + } + ), + 'manager' => [ + // FIXME - manager writes are disabled. This kinda works but it leaks errors all over the place. Not cool. + // '$ref' => (new AttributeMapping())->ignoreWrite()->ignoreRead(), + // 'displayName' => (new AttributeMapping())->ignoreWrite()->ignoreRead(), + // NOTE: you could probably do a 'plain' Eloquent mapping here, but we don't for future-proofing + 'value' => (new AttributeMapping())->setAdd( + function ($value, &$object) { + \Log::error("Manager-Add: $value"); //FIXME + $manager = User::find($value); + if ($manager) { + $object->manager_id = $manager->id; + } + } + )->setReplace( + function ($value, &$object) { + \Log::error("Manager-Replace: $value"); //FIXME + $manager = User::find($value); + if ($manager) { + $object->manager_id = $manager->id; + } + } + )->setRead( + function (&$object) { + \Log::error("Weird manager reader firing..."); //FIXME + return $object->manager_id; + } + ), + ] + ]; + + return $config; + } + +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index c4110a5897..29e581709f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -8,6 +8,7 @@ use App\Models\Component; use App\Models\Consumable; use App\Models\License; use App\Models\Setting; +use App\Models\SnipeSCIMConfig; use App\Observers\AccessoryObserver; use App\Observers\AssetObserver; use App\Observers\ComponentObserver; @@ -80,6 +81,8 @@ class AppServiceProvider extends ServiceProvider if ($this->app->environment(['local', 'develop'])) { $this->app->register(\Laravel\Dusk\DuskServiceProvider::class); } + + $this->app->singleton('ArieTimmerman\Laravel\SCIMServer\SCIMConfig', SnipeSCIMConfig::class); // this overrides the default SCIM configuration with our own } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 16a22d8660..447f1bc300 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -24,7 +24,7 @@ class RouteServiceProvider extends ServiceProvider $this->mapWebRoutes(); - // + require base_path('routes/scim.php'); }); } diff --git a/composer.json b/composer.json index d3261eadfc..712164f74d 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "ext-mbstring": "*", "ext-pdo": "*", "alek13/slack": "^2.0", + "arietimmerman/laravel-scim-server": "^0.5.5", "bacon/bacon-qr-code": "^2.0", "barryvdh/laravel-debugbar": "^3.6", "barryvdh/laravel-dompdf": "^1.0", @@ -61,7 +62,6 @@ "rollbar/rollbar-laravel": "^7.0", "spatie/laravel-backup": "^6.16", "tecnickcom/tc-lib-barcode": "^1.15", - "tightenco/ziggy": "v1.2.0", "unicodeveloper/laravel-password": "^1.0", "watson/validating": "^6.1" }, diff --git a/composer.lock b/composer.lock index 68671abb84..42b5f2e9a0 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": "442a6af235589e35cfcaa7e5e39e75ec", + "content-hash": "448c7508ab99eb86eb62e5cac3e9ee59", "packages": [ { "name": "alek13/slack", @@ -72,6 +72,65 @@ ], "time": "2021-10-20T22:52:32+00:00" }, + { + "name": "arietimmerman/laravel-scim-server", + "version": "v0.5.5", + "source": { + "type": "git", + "url": "https://github.com/arietimmerman/laravel-scim-server.git", + "reference": "8fb5b1cc0d28ace820b5b38a543d801fd49ada90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/arietimmerman/laravel-scim-server/zipball/8fb5b1cc0d28ace820b5b38a543d801fd49ada90", + "reference": "8fb5b1cc0d28ace820b5b38a543d801fd49ada90", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0", + "illuminate/database": "^6.0|^7.0|^8.0", + "illuminate/support": "^6.0|^7.0|^8.0", + "php": "^7.0|^8.0", + "tmilos/scim-filter-parser": "^1.3", + "tmilos/scim-schema": "^0.1.0" + }, + "require-dev": { + "laravel/legacy-factories": "*", + "orchestra/testbench": "^5.0|^6.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "ArieTimmerman\\Laravel\\SCIMServer\\ServiceProvider" + ], + "aliases": { + "SCIMServerHelper": "ArieTimmerman\\Laravel\\SCIMServer\\Helper" + } + } + }, + "autoload": { + "psr-4": { + "ArieTimmerman\\Laravel\\SCIMServer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Arie Timmerman", + "email": "arietimmerman@gmail.com" + } + ], + "description": "Laravel Package for creating a SCIM server", + "support": { + "issues": "https://github.com/arietimmerman/laravel-scim-server/issues", + "source": "https://github.com/arietimmerman/laravel-scim-server/tree/v0.5.5" + }, + "time": "2022-02-03T20:56:31+00:00" + }, { "name": "asm89/stack-cors", "version": "v2.1.1", @@ -11030,72 +11089,6 @@ ], "time": "2021-12-31T09:40:23+00:00" }, - { - "name": "tightenco/ziggy", - "version": "v1.2.0", - "source": { - "type": "git", - "url": "https://github.com/tighten/ziggy.git", - "reference": "147804d5f3e98b897fc1ed15efc2807f1099cf83" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tighten/ziggy/zipball/147804d5f3e98b897fc1ed15efc2807f1099cf83", - "reference": "147804d5f3e98b897fc1ed15efc2807f1099cf83", - "shasum": "" - }, - "require": { - "laravel/framework": ">=5.4@dev" - }, - "require-dev": { - "orchestra/testbench": "^6.0", - "phpunit/phpunit": "^9.2" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Tightenco\\Ziggy\\ZiggyServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Tightenco\\Ziggy\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Coulbourne", - "email": "daniel@tighten.co" - }, - { - "name": "Jake Bathman", - "email": "jake@tighten.co" - }, - { - "name": "Jacob Baker-Kretzmar", - "email": "jacob@tighten.co" - } - ], - "description": "Generates a Blade directive exporting all of your named Laravel routes. Also provides a nice route() helper function in JavaScript.", - "homepage": "https://github.com/tighten/ziggy", - "keywords": [ - "Ziggy", - "javascript", - "laravel", - "routes" - ], - "support": { - "issues": "https://github.com/tighten/ziggy/issues", - "source": "https://github.com/tighten/ziggy/tree/v1.2.0" - }, - "time": "2021-05-24T22:46:59+00:00" - }, { "name": "tijsverkoyen/css-to-inline-styles", "version": "2.2.4", @@ -11149,6 +11142,199 @@ }, "time": "2021-12-08T09:12:39+00:00" }, + { + "name": "tmilos/lexer", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/tmilos/lexer.git", + "reference": "e7885595614759f1da2ff79b66e3fb26d7f875fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tmilos/lexer/zipball/e7885595614759f1da2ff79b66e3fb26d7f875fa", + "reference": "e7885595614759f1da2ff79b66e3fb26d7f875fa", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~5.6", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tmilos\\Lexer\\": "src/", + "Tests\\Tmilos\\Lexer\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milos Tomic", + "email": "tmilos@gmail.com" + } + ], + "description": "Lexical analyzer with individual token definition with regular expressions", + "keywords": [ + "lexer", + "parser" + ], + "support": { + "issues": "https://github.com/tmilos/lexer/issues", + "source": "https://github.com/tmilos/lexer/tree/master" + }, + "time": "2016-12-21T11:22:39+00:00" + }, + { + "name": "tmilos/scim-filter-parser", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/tmilos/scim-filter-parser.git", + "reference": "cfd9ba1f33e1e15adcab2481bffd74cb9fb35704" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tmilos/scim-filter-parser/zipball/cfd9ba1f33e1e15adcab2481bffd74cb9fb35704", + "reference": "cfd9ba1f33e1e15adcab2481bffd74cb9fb35704", + "shasum": "" + }, + "require": { + "tmilos/lexer": "^1.0", + "tmilos/value": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tmilos\\ScimFilterParser\\": "src/", + "Tests\\Tmilos\\ScimFilterParser\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milos Tomic", + "email": "tmilos@gmail.com" + } + ], + "description": "System for Cross-domain Identity Management SCIM AST filter parser PHP library", + "keywords": [ + "SCIM AST", + "SCIM filter parser", + "SCIM parser", + "ast", + "parser", + "scim", + "simplecloud" + ], + "support": { + "issues": "https://github.com/tmilos/scim-filter-parser/issues", + "source": "https://github.com/tmilos/scim-filter-parser/tree/master" + }, + "time": "2017-01-19T11:17:42+00:00" + }, + { + "name": "tmilos/scim-schema", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/tmilos/scim-schema.git", + "reference": "bb871e667b33080b4cd36d7a9b2ac2cdbf796062" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tmilos/scim-schema/zipball/bb871e667b33080b4cd36d7a9b2ac2cdbf796062", + "reference": "bb871e667b33080b4cd36d7a9b2ac2cdbf796062", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.6", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Tmilos\\ScimSchema\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milos Tomic", + "email": "tmilos@gmail.com" + } + ], + "description": "SCIM schema library", + "support": { + "issues": "https://github.com/tmilos/scim-schema/issues", + "source": "https://github.com/tmilos/scim-schema/tree/master" + }, + "time": "2017-11-25T22:18:16+00:00" + }, + { + "name": "tmilos/value", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/tmilos/value.git", + "reference": "9e78ad9c026b14cacec1a27552ee0ada9d7d1c06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tmilos/value/zipball/9e78ad9c026b14cacec1a27552ee0ada9d7d1c06", + "reference": "9e78ad9c026b14cacec1a27552ee0ada9d7d1c06", + "shasum": "" + }, + "require": { + "php": ">=5.5.1" + }, + "require-dev": { + "moontoast/math": "~1.1", + "phpunit/phpunit": "~4.8", + "ramsey/uuid": "^3.3", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "autoload": { + "psr-0": { + "Tmilos\\Value\\": "src/", + "Tmilos\\Value\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Milos Tomic", + "email": "tmilos@gmail.com", + "homepage": "https://github.com/tmilos/", + "role": "Developer" + } + ], + "support": { + "issues": "https://github.com/tmilos/value/issues", + "source": "https://github.com/tmilos/value/tree/master" + }, + "time": "2016-06-06T10:22:16+00:00" + }, { "name": "unicodeveloper/laravel-password", "version": "1.0.4", @@ -13474,5 +13660,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.1.0" } diff --git a/config/app.php b/config/app.php index d9fc45bb09..ba56b42e33 100755 --- a/config/app.php +++ b/config/app.php @@ -342,7 +342,6 @@ return [ Laravel\Passport\PassportServiceProvider::class, Laravel\Tinker\TinkerServiceProvider::class, Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, - Tightenco\Ziggy\ZiggyServiceProvider::class, // Laravel routes in vue Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class, /* diff --git a/config/scim.php b/config/scim.php new file mode 100644 index 0000000000..3008e2f07e --- /dev/null +++ b/config/scim.php @@ -0,0 +1,5 @@ + false +]; diff --git a/public/js/snipeit.js b/public/js/snipeit.js deleted file mode 100644 index 81c79c884b..0000000000 Binary files a/public/js/snipeit.js and /dev/null differ diff --git a/resources/assets/js/components/importer/importer-file.vue b/resources/assets/js/components/importer/importer-file.vue index 2f692db01c..356d75c5c9 100644 --- a/resources/assets/js/components/importer/importer-file.vue +++ b/resources/assets/js/components/importer/importer-file.vue @@ -100,6 +100,7 @@ - - @routes diff --git a/routes/scim.php b/routes/scim.php new file mode 100644 index 0000000000..d8d8a8fdbc --- /dev/null +++ b/routes/scim.php @@ -0,0 +1,38 @@ +group(function () { + SCIMRouteProvider::routes( + [ + /* + * If we leave public_routes as 'true', the public routes will load *now* and + * be jammed into the same middleware that these private routes are loaded + * with. That's bad, because these routes are *supposed* to be public. + * + * We loaded them a few lines above, *first*, otherwise the various + * fallback routes in the library defined within these *secured* routes + * will "take over" the above routes - and then you will end up losing + * like 4 hours of your life trying to figure out why the public routes + * aren't quite working right. Ask me how I know (BMW, 3/19/2022) + */ + 'public_routes' => false + ] + ); + + SCIMRouteProvider::meRoutes(); +}); // ->can('superuser');