3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-04-02 22:11:01 +00:00
Files
snipe-it/app/Models/SnipeSCIMConfig.php
2026-03-13 15:55:28 +00:00

250 lines
11 KiB
PHP

<?php
namespace App\Models;
use ArieTimmerman\Laravel\SCIMServer\Attribute\AttributeMapping;
use ArieTimmerman\Laravel\SCIMServer\SCIM\Schema;
use ArieTimmerman\Laravel\SCIMServer\SCIMConfig;
use Illuminate\Database\Eloquent\Model;
class SnipeSCIMConfig extends SCIMConfig
{
public function getUserConfig()
{
// Much of this is copied verbatim from the library, then adjusted for our needs
/*
more snipe-it attributes I'd like to check out (to map to 'enterprise' maybe?):
- website
- notes?
- remote???
- location_id ?
- company_id to "organization?"
*/
$user_prefix = 'urn:ietf:params:scim:schemas:core:2.0:User:';
$enterprise_prefix = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:';
return [
// Set to 'null' to make use of auth.providers.users.model (App\User::class)
'class' => SCIMUser::class,
'validations' => [
$user_prefix.'userName' => 'required',
$user_prefix.'displayName' => 'nullable|string',
$user_prefix.'name.givenName' => 'required',
$user_prefix.'name.familyName' => 'nullable|string',
$user_prefix.'externalId' => 'nullable|string',
$user_prefix.'emails' => 'nullable|array',
$user_prefix.'emails.*.value' => 'nullable|email',
$user_prefix.'active' => 'boolean',
$user_prefix.'phoneNumbers' => 'nullable|array',
$user_prefix.'phoneNumbers.*.value' => 'nullable|string',
$user_prefix.'addresses' => 'nullable|array',
$user_prefix.'addresses.*.streetAddress' => 'nullable|string',
$user_prefix.'addresses.*.locality' => 'nullable|string',
$user_prefix.'addresses.*.region' => 'nullable|string',
$user_prefix.'addresses.*.postalCode' => 'nullable|string',
$user_prefix.'addresses.*.country' => 'nullable|string',
$user_prefix.'title' => 'nullable|string',
$user_prefix.'preferredLanguage' => 'nullable|string',
// Enterprise validations:
$enterprise_prefix.'employeeNumber' => 'nullable|string',
$enterprise_prefix.'department' => 'nullable|string',
$enterprise_prefix.'manager' => 'nullable',
$enterprise_prefix.'manager.value' => 'nullable|string',
],
'singular' => 'User',
'schema' => [Schema::SCHEMA_USER],
// eager loading
'withRelations' => [],
'map_unmapped' => false,
// 'unmapped_namespace' => 'urn:ietf:params:scim:schemas:laravel:unmapped',
'description' => 'User Account',
// Map a SCIM attribute to an attribute of the object.
'mapping' => [
'id' => (new AttributeMapping)->setRead(
function (&$object) {
return (string) $object->id;
}
)->disableWrite(),
'externalId' => AttributeMapping::eloquent('scim_externalid'), // FIXME - I have a PR that changes a lot of this.
'meta' => [
'created' => AttributeMapping::eloquent('created_at')->disableWrite(),
'lastModified' => AttributeMapping::eloquent('updated_at')->disableWrite(),
'location' => (new AttributeMapping)->setRead(
function ($object) {
return route(
'scim.resource',
[
'resourceType' => 'Users',
'resourceObject' => $object->id,
]
);
}
)->disableWrite(),
'resourceType' => AttributeMapping::constant('User'),
],
'schemas' => AttributeMapping::constant(
[
'urn:ietf:params:scim:schemas:core:2.0:User',
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User',
]
)->ignoreWrite(),
'urn:ietf:params:scim:schemas:core:2.0:User' => [
'userName' => AttributeMapping::eloquent('username'),
'name' => [
'formatted' => (new AttributeMapping)->ignoreWrite()->setRead(
function (&$object) {
return $object->getFullNameAttribute();
}
),
'familyName' => AttributeMapping::eloquent('last_name'),
'givenName' => AttributeMapping::eloquent('first_name'),
'middleName' => null,
'honorificPrefix' => null,
'honorificSuffix' => null,
],
'displayName' => AttributeMapping::eloquent('display_name'),
'nickName' => null,
'profileUrl' => null,
'title' => AttributeMapping::eloquent('jobtitle'),
'userType' => null,
'preferredLanguage' => AttributeMapping::eloquent('locale'), // Section 5.3.5 of [RFC7231]
'locale' => null, // see RFC5646
'timezone' => null, // see RFC6557
'active' => (new AttributeMapping)->setAdd(
function ($value, &$object) {
$object->activated = $value;
}
)->setReplace(
function ($value, &$object) {
$object->activated = $value;
}
)->setRead(
// this works as specified.
function (&$object) {
return (bool) $object->activated;
}
),
'password' => AttributeMapping::eloquent('password')->disableRead(),
// Multi-Valued Attributes
'emails' => [[
'value' => AttributeMapping::eloquent('email'),
'display' => null,
'type' => AttributeMapping::constant('work')->ignoreWrite(),
'primary' => AttributeMapping::constant(true)->ignoreWrite(),
]],
'phoneNumbers' => [[
'value' => AttributeMapping::eloquent('phone'),
'display' => null,
'type' => AttributeMapping::constant('work')->ignoreWrite(),
'primary' => AttributeMapping::constant(true)->ignoreWrite(),
]],
'ims' => [[
'value' => null,
'display' => null,
'type' => null,
'primary' => null,
]], // Instant messaging addresses for the User
'photos' => [[
'value' => null,
'display' => null,
'type' => null,
'primary' => null,
]],
'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?
]],
'groups' => [[
'value' => null,
'$ref' => null,
'display' => null,
'type' => null,
]],
'entitlements' => null,
'roles' => null,
'x509Certificates' => null,
],
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' => [
'employeeNumber' => AttributeMapping::eloquent('employee_num'),
'department' => (new AttributeMapping)->setAdd( // FIXME parent?
function ($value, &$object) {
$department = Department::where('name', $value)->first();
if ($department) {
$object->department_id = $department->id;
}
}
)->setReplace(
function ($value, &$object) {
$department = Department::where('name', $value)->first();
if ($department) {
$object->department_id = $department->id;
}
}
)->setRead(
function (&$object) {
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) {
$manager = User::find($value);
if ($manager) {
$object->manager_id = $manager->id;
}
}
)->setReplace(
function ($value, &$object) {
$manager = User::find($value);
if ($manager) {
$object->manager_id = $manager->id;
}
}
)->setRead(
function (&$object) {
return $object->manager_id;
}
),
],
],
],
];
}
}