diff --git a/.env.example b/.env.example index aec53104a3..0431efeb7e 100644 --- a/.env.example +++ b/.env.example @@ -40,3 +40,4 @@ BROWSER_CACHE=true VUE_APP_WEBSOCKET_PROVIDER=socket.io VUE_APP_WEBSOCKET_PROVIDER_URL=ws:127.0.0.1:1234 VUE_APP_COLLABORATIVE_ENABLED=true +SAML_SP_DESTINATION="https://keycloak.processmaker.net/realms/realmname/broker/saml/endpoint" diff --git a/composer.json b/composer.json index 5af8de9678..718e7baa05 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "require": { "php": "^8.2", "babenkoivan/elastic-scout-driver": "^3.0", + "codegreencreative/laravel-samlidp": "^5.2", "composer/semver": "^3.3", "darkaonline/l5-swagger": "^8.3", "doctrine/dbal": "^3.5", diff --git a/composer.lock b/composer.lock index a5a0c0eeed..a524d69f42 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": "08d1c39d3fb9b2c3bd58193f03966e91", + "content-hash": "8155b4e65835b2a1178b71cc5124aa92", "packages": [ { "name": "aws/aws-crt-php", @@ -488,6 +488,59 @@ ], "time": "2023-01-15T23:15:59+00:00" }, + { + "name": "codegreencreative/laravel-samlidp", + "version": "v5.2.7", + "source": { + "type": "git", + "url": "https://github.com/codegreencreative/laravel-samlidp.git", + "reference": "e623f4ac513047ed679a5484d6f391cc3c02f0e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/codegreencreative/laravel-samlidp/zipball/e623f4ac513047ed679a5484d6f391cc3c02f0e4", + "reference": "e623f4ac513047ed679a5484d6f391cc3c02f0e4", + "shasum": "" + }, + "require": { + "illuminate/routing": "^7.0|^8.0|^9.0|^10.0", + "illuminate/support": "^7.0|^8.0|^9.0|^10.0", + "litesaml/lightsaml": "^4.0", + "php": "^7.2.5|^8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "CodeGreenCreative\\SamlIdp\\LaravelSamlIdpServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "CodeGreenCreative\\SamlIdp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Make your PHP Laravel application an Identification Provider using SAML 2.0. This package allows you to implement your own Identification Provider (idP) using the SAML 2.0 standard to be used with supporting SAML 2.0 Service Providers (SP).", + "keywords": [ + "SAML 2.0", + "SSO", + "acl", + "auth", + "idp", + "laravel", + "saml" + ], + "support": { + "issues": "https://github.com/codegreencreative/laravel-samlidp/issues", + "source": "https://github.com/codegreencreative/laravel-samlidp/tree/v5.2.7" + }, + "time": "2023-08-02T14:30:32+00:00" + }, { "name": "composer/semver", "version": "3.3.2", @@ -4742,6 +4795,75 @@ ], "time": "2021-06-28T04:27:21+00:00" }, + { + "name": "litesaml/lightsaml", + "version": "v4.1.6", + "source": { + "type": "git", + "url": "https://github.com/litesaml/lightsaml.git", + "reference": "b6aa6f41c3a051a52e39ddc3a7b753a8601bee69" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/litesaml/lightsaml/zipball/b6aa6f41c3a051a52e39ddc3a7b753a8601bee69", + "reference": "b6aa6f41c3a051a52e39ddc3a7b753a8601bee69", + "shasum": "" + }, + "require": { + "php": ">=7.4", + "psr/event-dispatcher": "^1.0", + "robrichards/xmlseclibs": "~2.0|~3.0|~4.0", + "symfony/http-foundation": "~5.0|~6.0" + }, + "require-dev": { + "litesaml/schemas": "~1.0.0", + "marcocesarato/php-conventional-changelog": "^1.15", + "monolog/monolog": "^2.0|^3.0", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "~8.4|~9.5", + "pimple/pimple": "~3.0", + "squizlabs/php_codesniffer": "^3.6", + "symfony/css-selector": "~5.0|~6.0", + "symfony/dom-crawler": "~5.0|~6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "LightSaml\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "William", + "email": "work@suppo.fr" + }, + { + "name": "Milos Tomic", + "email": "tmilos@gmail.com", + "homepage": "https://github.com/tmilos/", + "role": "Developer" + } + ], + "description": "SAML 2.0 PHP library", + "keywords": [ + "SAML 2.0", + "Single Logout", + "Single SignOn", + "library", + "lightSAML", + "php" + ], + "support": { + "docs": "https://docs.litesaml.com", + "issues": "https://github.com/litesaml/lightsaml/issues", + "source": "https://github.com/litesaml/lightsaml" + }, + "time": "2023-04-14T14:11:32+00:00" + }, { "name": "maennchen/zipstream-php", "version": "3.1.0", @@ -7869,6 +7991,48 @@ ], "time": "2023-04-15T23:01:58+00:00" }, + { + "name": "robrichards/xmlseclibs", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/robrichards/xmlseclibs.git", + "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df", + "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">= 5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "RobRichards\\XMLSecLibs\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "A PHP library for XML Security", + "homepage": "https://github.com/robrichards/xmlseclibs", + "keywords": [ + "security", + "signature", + "xml", + "xmldsig" + ], + "support": { + "issues": "https://github.com/robrichards/xmlseclibs/issues", + "source": "https://github.com/robrichards/xmlseclibs/tree/3.1.1" + }, + "time": "2020-09-05T13:00:25+00:00" + }, { "name": "spatie/fractalistic", "version": "2.9.5", diff --git a/config/filesystems.php b/config/filesystems.php index e2744e6adf..7d9c7a0ae4 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -109,6 +109,11 @@ 'visibility' => 'public', ], + 'samlidp' => [ + 'driver' => 'local', + 'root' => storage_path() . '/samlidp', + ], + ], /* diff --git a/config/samlidp.php b/config/samlidp.php new file mode 100644 index 0000000000..d1efe55cda --- /dev/null +++ b/config/samlidp.php @@ -0,0 +1,69 @@ + false, + // Define the email address field name in the users table + 'email_field' => 'email', + // Define the name field in the users table + 'name_field' => 'name', + // The URI to your login page + 'login_uri' => 'login', + // Log out of the IdP after SLO + 'logout_after_slo' => env('LOGOUT_AFTER_SLO', false), + // The URI to the saml metadata file, this describes your idP + 'issuer_uri' => 'saml/metadata', + // The certificate + 'cert' => env('SAMLIDP_CERT'), + // Name of the certificate PEM file, ignored if cert is used + 'certname' => 'cert.pem', + // The certificate key + 'key' => env('SAMLIDP_KEY'), + // Name of the certificate key PEM file, ignored if key is used + 'keyname' => 'key.pem', + // Encrypt requests and responses + 'encrypt_assertion' => true, + // Make sure messages are signed + 'messages_signed' => true, + // Defind what digital algorithm you want to use + 'digest_algorithm' => \RobRichards\XMLSecLibs\XMLSecurityDSig::SHA1, + // list of all service providers + 'sp' => [ + // Base64 encoded ACS URL + base64_encode(env('SAML_SP_DESTINATION', '')) => [ + 'destination' => env('SAML_SP_DESTINATION', ''), + 'logout' => '', + // SP certificate + 'certificate' => '', + // Turn off auto appending of the idp query param + 'query_params' => false, + // Turn off the encryption of the assertion per SP + 'encrypt_assertion' => false, + ], + ], + + // If you need to redirect after SLO depending on SLO initiator + // key is beginning of HTTP_REFERER value from SERVER, value is redirect path + 'sp_slo_redirects' => [ + // 'https://example.com' => 'https://example.com', + ], + + // All of the Laravel SAML IdP event / listener mappings. + 'events' => [ + 'CodeGreenCreative\SamlIdp\Events\Assertion' => [], + 'Illuminate\Auth\Events\Logout' => ['CodeGreenCreative\SamlIdp\Listeners\SamlLogout'], + 'Illuminate\Auth\Events\Authenticated' => ['CodeGreenCreative\SamlIdp\Listeners\SamlAuthenticated'], + 'Illuminate\Auth\Events\Login' => ['CodeGreenCreative\SamlIdp\Listeners\SamlLogin'], + ], + + // List of guards saml idp will catch Authenticated, Login and Logout events + 'guards' => ['web'], +]; diff --git a/resources/views/auth/newLogin.blade.php b/resources/views/auth/newLogin.blade.php index 90bf44ee61..015a7e0605 100644 --- a/resources/views/auth/newLogin.blade.php +++ b/resources/views/auth/newLogin.blade.php @@ -3,7 +3,7 @@ - + @@ -44,6 +44,9 @@ @if (session()->has('login-error'))
{{ session()->get('login-error')}}
@endif + + @samlidp +
@@ -110,7 +113,7 @@ if (isMobileDevice) { document.cookie = "isMobile=true" } - + const togglePassword = document.querySelector('#togglePassword'); const password = document.querySelector('#password'); diff --git a/storage/samlidp/.gitignore b/storage/samlidp/.gitignore new file mode 100755 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/storage/samlidp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/Feature/AuthTest.php b/tests/Feature/AuthTest.php index a0724f77eb..d5bf471b8d 100644 --- a/tests/Feature/AuthTest.php +++ b/tests/Feature/AuthTest.php @@ -21,7 +21,7 @@ public function testAuthLoginAndLogout() $user = User::factory()->create(); Auth::login($user); $this->assertEquals($user->id, Auth::id()); - Auth::logout(); + Auth::logoutCurrentDevice(); $this->assertNull(Auth::user()); } diff --git a/tests/Feature/RedirectTest.php b/tests/Feature/RedirectTest.php index dd3f2a2fa8..0da2c3e6b3 100644 --- a/tests/Feature/RedirectTest.php +++ b/tests/Feature/RedirectTest.php @@ -27,7 +27,7 @@ public function test401RedirectsToLogin() $response = $this->get('/requests'); $response->assertStatus(200); $response->assertViewIs('requests.index'); - Auth::logout(); + Auth::logoutCurrentDevice(); $response = $this->get('/requests'); //302 because we want to make sure they are being redirected $response->assertStatus(302); diff --git a/tests/Feature/SecurityLoggerTest.php b/tests/Feature/SecurityLoggerTest.php index 339c406964..e553451c5d 100644 --- a/tests/Feature/SecurityLoggerTest.php +++ b/tests/Feature/SecurityLoggerTest.php @@ -43,7 +43,11 @@ public function testLogSecurityEvents() $this->assertDatabaseHas('security_logs', ['event' => 'login', 'user_id' => $user->id]); // Attempt to logout - Auth::logout(); + if (in_array(Auth::getDefaultDriver(), config('samlidp.guards'))) { + return redirect('saml/logout'); + } else { + Auth::logout(); + } $this->assertDatabaseHas('security_logs', ['event' => 'logout', 'user_id' => $user->id]); // Disable security logging