Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ jobs:
strategy:
matrix:
php: [8.0, 8.1, 8.2]
laravel: [8.*, 9.*, 10.*, 11.*, 12.*]
laravel: [10.*, 11.*, 12.*]
exclude:
- laravel: 8.*
php: 8.2
- laravel: 10.*
php: 8.0
- laravel: 11.*
Expand Down Expand Up @@ -46,4 +44,24 @@ jobs:
composer require "illuminate/console:${{ matrix.laravel }}" "illuminate/database:${{ matrix.laravel }}" "illuminate/support:${{ matrix.laravel }}" --no-interaction --no-update
composer update
- name: Run tests
run: vendor/bin/phpunit
run: vendor/bin/phpunit

docker:
runs-on: ubuntu-latest
needs: tests
if: github.event_name == 'push' || github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
122 changes: 116 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,122 @@ RUN jq '.repositories=[{"type": "path","url": "/laravel-scim-server"}]' ./compos
RUN composer require arietimmerman/laravel-scim-server @dev && \
composer require laravel/tinker

RUN touch ./.database.sqlite && \
echo "DB_CONNECTION=sqlite" >> ./.env && \
echo "DB_DATABASE=/.database.sqlite" >> ./.env && \
echo "APP_URL=http://localhost:18123" >> ./.env
RUN touch /example/database.sqlite && \
echo "DB_CONNECTION=sqlite" >> /example/.env && \
echo "DB_DATABASE=/example/database.sqlite" >> /example/.env && \
echo "APP_URL=http://localhost:18123" >> /example/.env


# Add migration for groups table using heredoc
RUN cat > /example/database/migrations/2021_01_01_000001_create_groups_table.php <<'EOM'
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
public function up(): void
{
Schema::create('groups', function (Blueprint $table) {
$table->id();
$table->string('displayName')->unique();
$table->timestamps();
});
}

public function down(): void
{
Schema::dropIfExists('groups');
}
};
EOM

# Add Group model
RUN cat > app/Models/Group.php <<'EOM'
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Group extends Model
{
use HasFactory;

protected $fillable = ['displayName'];
}
EOM

# Add Custom SCIM Config overriding Group model class
RUN mkdir -p app/SCIM && cat > app/SCIM/CustomSCIMConfig.php <<'EOM'
<?php

namespace App\SCIM;

use ArieTimmerman\Laravel\SCIMServer\SCIMConfig as BaseSCIMConfig;

class CustomSCIMConfig extends BaseSCIMConfig
{
public function getGroupConfig()
{
$config = parent::getGroupConfig();
// Force the group model to the example app's Group model
$config['class'] = \App\Models\Group::class;
return $config;
}
}
EOM

# Override AppServiceProvider to register custom SCIMConfig binding
RUN cat > app/Providers/AppServiceProvider.php <<'EOM'
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use ArieTimmerman\Laravel\SCIMServer\SCIMConfig as BaseSCIMConfig;
use App\SCIM\CustomSCIMConfig;

class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(BaseSCIMConfig::class, CustomSCIMConfig::class);
}

public function boot(): void
{
// Additional boot logic if needed
}
}
EOM

# Add Group factory
RUN cat > database/factories/GroupFactory.php <<'EOM'
<?php

namespace Database\Factories;

use App\Models\Group;
use Illuminate\Database\Eloquent\Factories\Factory;

class GroupFactory extends Factory
{
protected $model = Group::class;

public function definition(): array
{
return [
'displayName' => $this->faker->unique()->company(),
];
}
}
EOM

# Run migrations and seed demo data
RUN php artisan migrate && \
echo "User::factory()->count(100)->create();" | php artisan tinker
echo "User::factory()->count(100)->create(); App\\Models\\Group::factory()->count(10)->create();" | php artisan tinker

CMD php artisan serve --host=0.0.0.0 --port=8000
CMD ["php","artisan","serve","--host=0.0.0.0","--port=8000"]
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
],
"require": {
"php": "^8.0",
"illuminate/database": "^8.0|^9.0|^10.0|^11.0|^12.0",
"illuminate/support": "^8.0|^9.0|^10.0|^11.0|^12.0",
"illuminate/console": "^8.0|^9.0|^10.0|^11.0|^12.0",
"illuminate/database": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/console": "^10.0|^11.0|^12.0",
"tmilos/scim-schema": "^0.1.0",
"tmilos/scim-filter-parser": "^1.3"
},
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ services:
ports:
# forward xdebug ports
- "127.0.0.1:18123:8000"
working_dir: /laravel-scim-server
working_dir: /example
environment:
- XDEBUG_MODE=debug
- XDEBUG_SESSION=1
Expand Down
54 changes: 27 additions & 27 deletions src/RouteProvider.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?php

namespace ArieTimmerman\Laravel\SCIMServer;

use ArieTimmerman\Laravel\SCIMServer\Middleware\SCIMHeaders;
use Illuminate\Support\Facades\Route;
use Illuminate\Routing\Middleware\SubstituteBindings;

/**
* Helper class for the URL shortener
Expand All @@ -19,22 +22,19 @@ public static function routes(array $options = [])

Route::prefix(static::$prefix)->group(
function () use ($options) {
Route::prefix('v2')->middleware(
[
// TODO: Not loading this middleware introduces resolve issues. But having it, might slow things down.
\Illuminate\Routing\Middleware\SubstituteBindings::class,
'ArieTimmerman\Laravel\SCIMServer\Middleware\SCIMHeaders'
]
)->group(
Route::prefix('v2')->middleware([
SubstituteBindings::class,
SCIMHeaders::class,
])->group(
function () use ($options) {
static::allRoutes($options);
}
);

Route::get('v1', '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@wrongVersion');
Route::get('v1', [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'wrongVersion']);
Route::prefix('v1')->group(
function () {
Route::fallback('\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@wrongVersion');
Route::fallback([\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'wrongVersion']);
}
);
}
Expand All @@ -44,47 +44,47 @@ function () {
public static function meRoutes(array $options = [])
{
Route::prefix(static::$prefix)->group(function () {
Route::get("/v2/Me", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\MeController@getMe')->name('scim.me.get');
Route::put('/v2/Me', '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\MeController@replaceMe')->name('scim.me.put');
Route::get("/v2/Me", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\MeController::class, 'getMe'])->name('scim.me.get');
Route::put('/v2/Me', [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\MeController::class, 'replaceMe'])->name('scim.me.put');
});
}

public static function meRoutePost(array $options = [])
{
Route::prefix(static::$prefix)->group(function () {
Route::post('/v2/Me', '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\MeController@createMe')->name('scim.me.post');
Route::post('/v2/Me', [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\MeController::class, 'createMe'])->name('scim.me.post');
});
}

public static function publicRoutes(array $options = [])
{
Route::prefix(static::$prefix)->group(function () {
Route::get("/v2/ServiceProviderConfig", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ServiceProviderController@index')->name('scim.serviceproviderconfig');
Route::get("/v2/ServiceProviderConfig", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ServiceProviderController::class, 'index'])->name('scim.serviceproviderconfig');

Route::get("/v2/Schemas", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\SchemaController@index');
Route::get("/v2/Schemas/{id}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\SchemaController@show')->name('scim.schemas');
Route::get("/v2/Schemas", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\SchemaController::class, 'index']);
Route::get("/v2/Schemas/{id}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\SchemaController::class, 'show'])->name('scim.schemas');

Route::get("/v2/ResourceTypes", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceTypesController@index');
Route::get("/v2/ResourceTypes/{id}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceTypesController@show')->name('scim.resourcetype');
Route::get("/v2/ResourceTypes", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceTypesController::class, 'index']);
Route::get("/v2/ResourceTypes/{id}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceTypesController::class, 'show'])->name('scim.resourcetype');
});
}

private static function allRoutes(array $options = [])
{
Route::post('.search', '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@notImplemented');
Route::post('.search', [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'notImplemented']);

Route::post("/Bulk", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\BulkController@processBulkRequest');
Route::post("/Bulk", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\BulkController::class, 'processBulkRequest']);

// TODO: Use the attributes parameters ?attributes=userName, excludedAttributes=asdg,asdg (respect "returned" settings "always")
Route::get('/{resourceType}/{resourceObject}', '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@show')->name('scim.resource');
Route::get("/{resourceType}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@index')->name('scim.resources');
Route::post("/{resourceType}/.search", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@search');
Route::post("/{resourceType}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@create');
Route::get('/{resourceType}/{resourceObject}', [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'show'])->name('scim.resource');
Route::get("/{resourceType}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'index'])->name('scim.resources');
Route::post("/{resourceType}/.search", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'search']);
Route::post("/{resourceType}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'create']);

Route::put("/{resourceType}/{resourceObject}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@replace');
Route::patch("/{resourceType}/{resourceObject}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@update');
Route::delete("/{resourceType}/{resourceObject}", '\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@delete');
Route::put("/{resourceType}/{resourceObject}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'replace']);
Route::patch("/{resourceType}/{resourceObject}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'update']);
Route::delete("/{resourceType}/{resourceObject}", [\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'delete']);

Route::fallback('\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController@notImplemented');
Route::fallback([\ArieTimmerman\Laravel\SCIMServer\Http\Controllers\ResourceController::class, 'notImplemented']);
}
}
5 changes: 5 additions & 0 deletions src/SCIMConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public function getConfigForResource($name)
return @$result[$name];
}

public function getGroupClass()
{
return Group::class;
}

public function getUserConfig()
{
return [
Expand Down
5 changes: 3 additions & 2 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

/**
* Laravel service provider for registering the routes and publishing the configuration.
*/
Expand All @@ -14,7 +15,7 @@ public function boot(\Illuminate\Routing\Router $router)
$this->loadMigrationsFrom(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'migrations');

$this->publishes([
__DIR__.'/../config/scim.php' => config_path('scim.php'),
__DIR__ . '/../config/scim.php' => config_path('scim.php'),
], 'laravel-scim');

// Match everything, except the Me routes
Expand Down Expand Up @@ -79,7 +80,7 @@ function ($id, $route) {
public function register()
{
$this->mergeConfigFrom(
__DIR__.'/../config/scim.php',
__DIR__ . '/../config/scim.php',
'scim'
);
}
Expand Down