From fc4579c47dd2c88029e36b53b66e657d024abfce Mon Sep 17 00:00:00 2001 From: Malek Tellissi Date: Sun, 13 Sep 2026 01:40:46 +0200 Subject: [PATCH] Add Nextcloud OAuth 2.0 login via laravel/socialite Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/deploy.yml | 3 + app/Http/Controllers/OAuthController.php | 34 ++ app/Providers/AppServiceProvider.php | 10 +- app/Providers/Filament/UserPanelProvider.php | 16 + composer.json | 2 + composer.lock | 600 ++++++++++++++++++- config/services.php | 7 + routes/web.php | 4 + 8 files changed, 673 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/OAuthController.php diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 7580fd9..e78511d 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -34,6 +34,9 @@ jobs: QUEUE_CONNECTION=sync LOG_CHANNEL=stderr GIT_COMMIT=${{ github.sha }} + OAUTH_CLOUDSPICESBLUE_ID=${{ secrets.OAUTH_CLOUDSPICESBLUE_ID }} + OAUTH_CLOUDSPICESBLUE_SECRETKEY=${{ secrets.OAUTH_CLOUDSPICESBLUE_SECRETKEY }} + OAUTH_CLOUDSPICESBLUE_REDIRECTURI=${{ vars.OAUTH_CLOUDSPICESBLUE_REDIRECTURI }} EOF - name: PHP-Quellverzeichnisse leeren diff --git a/app/Http/Controllers/OAuthController.php b/app/Http/Controllers/OAuthController.php new file mode 100644 index 0000000..8aad1a3 --- /dev/null +++ b/app/Http/Controllers/OAuthController.php @@ -0,0 +1,34 @@ +redirect(); + } + + public function callback(): RedirectResponse + { + $socialUser = Socialite::driver('nextcloud')->user(); + + $user = User::firstOrCreate( + ['email' => $socialUser->getEmail()], + [ + 'name' => $socialUser->getName() ?? $socialUser->getNickname() ?? $socialUser->getEmail(), + 'password' => Str::random(40), + ] + ); + + Auth::login($user, remember: true); + + return redirect('/dashboard'); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 63c90ff..b58ab8e 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -3,8 +3,10 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; -use App\Models\Product; // Richtiges Product-Model importieren -use App\Observers\ProductObserver; // ProductObserver importieren +use Illuminate\Support\Facades\Event; +use App\Models\Product; +use App\Observers\ProductObserver; +use SocialiteProviders\Manager\SocialiteWasCalled; class AppServiceProvider extends ServiceProvider { @@ -22,5 +24,9 @@ class AppServiceProvider extends ServiceProvider public function boot(): void { Product::observe(ProductObserver::class); + + Event::listen(function (SocialiteWasCalled $event) { + $event->extendSocialite('nextcloud', \SocialiteProviders\Nextcloud\Provider::class); + }); } } diff --git a/app/Providers/Filament/UserPanelProvider.php b/app/Providers/Filament/UserPanelProvider.php index 6796cae..fc08cf9 100644 --- a/app/Providers/Filament/UserPanelProvider.php +++ b/app/Providers/Filament/UserPanelProvider.php @@ -46,6 +46,22 @@ class UserPanelProvider extends PanelProvider NavigationGroup::make('Ressourcen'), NavigationGroup::make('CRM'), ]) + ->renderHook( + PanelsRenderHook::AUTH_LOGIN_FORM_AFTER, + fn () => new HtmlString( + '
' + . '
' + . '
' + . 'oder' + . '
' + . '
' + . '' + . '' + . 'Mit Nextcloud anmelden' + . '' + . '
' + ) + ) ->renderHook( PanelsRenderHook::SIDEBAR_FOOTER, fn () => new HtmlString( diff --git a/composer.json b/composer.json index aef153b..cf93fdf 100644 --- a/composer.json +++ b/composer.json @@ -9,9 +9,11 @@ "filament/filament": "^3.2", "flowframe/laravel-trend": "^0.3.0", "laravel/framework": "^11.9", + "laravel/socialite": "^5.31", "laravel/tinker": "^2.9", "leandrocfe/filament-apex-charts": "^3.1", "picqer/php-barcode-generator": "^3.3", + "socialiteproviders/nextcloud": "^4.0", "spatie/laravel-activitylog": "^4.9", "z3d0x/filament-logger": "^0.7.2" }, diff --git a/composer.lock b/composer.lock index d8e2d98..26b2a4f 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": "45cc716f18a426dc09aceb48f3a350d8", + "content-hash": "e8477e7313b54ea6c6a999f2afe73f6d", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -1419,6 +1419,72 @@ }, "time": "2026-06-12T16:57:28+00:00" }, + { + "name": "firebase/php-jwt", + "version": "v7.1.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/php-jwt.git", + "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/b374a5d1a4f1f67fadc2165cdb284645945e2fc0", + "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpfastcache/phpfastcache": "^9.2", + "phpseclib/phpseclib": "~3.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present", + "phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/googleapis/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/googleapis/php-jwt/issues", + "source": "https://github.com/googleapis/php-jwt/tree/v7.1.0" + }, + "time": "2026-06-11T17:54:14+00:00" + }, { "name": "flowframe/laravel-trend", "version": "v0.3.0", @@ -2441,6 +2507,78 @@ }, "time": "2026-08-18T20:28:54+00:00" }, + { + "name": "laravel/socialite", + "version": "v5.31.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/socialite.git", + "reference": "f721b2cbec327ab820bd6aabea6ab211cfcc9f08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/socialite/zipball/f721b2cbec327ab820bd6aabea6ab211cfcc9f08", + "reference": "f721b2cbec327ab820bd6aabea6ab211cfcc9f08", + "shasum": "" + }, + "require": { + "ext-json": "*", + "firebase/php-jwt": "^6.4|^7.0", + "guzzlehttp/guzzle": "^6.0|^7.0|^8.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0|^13.0", + "league/oauth1-client": "^1.11", + "php": "^8.1", + "phpseclib/phpseclib": "^4.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.18|^5.20|^6.47|^7.55|^8.36|^9.15|^10.8|^11.0", + "phpstan/phpstan": "^1.12.23", + "phpunit/phpunit": "^8.0|^9.3|^10.4|^11.5|^12.0" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Socialite": "Laravel\\Socialite\\Facades\\Socialite" + }, + "providers": [ + "Laravel\\Socialite\\SocialiteServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Socialite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.", + "homepage": "https://laravel.com", + "keywords": [ + "laravel", + "oauth" + ], + "support": { + "issues": "https://github.com/laravel/socialite/issues", + "source": "https://github.com/laravel/socialite" + }, + "time": "2026-08-31T13:49:19+00:00" + }, { "name": "laravel/tinker", "version": "v2.11.1", @@ -2975,6 +3113,82 @@ ], "time": "2026-07-09T11:49:27+00:00" }, + { + "name": "league/oauth1-client", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth1-client.git", + "reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/f9c94b088837eb1aae1ad7c4f23eb65cc6993055", + "reference": "f9c94b088837eb1aae1ad7c4f23eb65cc6993055", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=7.1||>=8.0" + }, + "require-dev": { + "ext-simplexml": "*", + "friendsofphp/php-cs-fixer": "^2.17", + "mockery/mockery": "^1.3.3", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5||9.5" + }, + "suggest": { + "ext-simplexml": "For decoding XML-based responses." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev", + "dev-develop": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth1\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Corlett", + "email": "bencorlett@me.com", + "homepage": "http://www.webcomm.com.au", + "role": "Developer" + } + ], + "description": "OAuth 1.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "bitbucket", + "identity", + "idp", + "oauth", + "oauth1", + "single sign on", + "trello", + "tumblr", + "twitter" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth1-client/issues", + "source": "https://github.com/thephpleague/oauth1-client/tree/v1.11.0" + }, + "time": "2024-12-10T19:59:05+00:00" + }, { "name": "league/uri", "version": "7.8.1", @@ -3980,6 +4194,75 @@ ], "time": "2025-09-03T16:03:54+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.1.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2025-09-24T15:06:41+00:00" + }, { "name": "phpoption/phpoption", "version": "1.10.0", @@ -4055,6 +4338,126 @@ ], "time": "2026-08-24T00:54:40+00:00" }, + { + "name": "phpseclib/phpseclib", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "bb7b959c8159957edae6f5084ebbac765d310e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/bb7b959c8159957edae6f5084ebbac765d310e16", + "reference": "bb7b959c8159957edae6f5084ebbac765d310e16", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^2|^3", + "php": ">=8.1", + "symfony/polyfill-php82": "^1.26" + }, + "require-dev": { + "brianium/paratest": "^7.22", + "ext-xml": "*", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpunit/phpunit": "^13", + "squizlabs/php_codesniffer": "^3.7", + "vimeo/psalm": "*" + }, + "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-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib4\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + }, + { + "name": "Jack Worman", + "email": "jack.worman@gmail.com", + "homepage": "https://jackworman.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "https://phpseclib.com/", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2026-08-26T12:15:13+00:00" + }, { "name": "picqer/php-barcode-generator", "version": "v3.3.0", @@ -4951,6 +5354,121 @@ ], "time": "2026-03-19T10:36:26+00:00" }, + { + "name": "socialiteproviders/manager", + "version": "4.9.2", + "source": { + "type": "git", + "url": "https://github.com/SocialiteProviders/Manager.git", + "reference": "35372dc62787e61e91cfec73f45fd5d5ae0f8891" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SocialiteProviders/Manager/zipball/35372dc62787e61e91cfec73f45fd5d5ae0f8891", + "reference": "35372dc62787e61e91cfec73f45fd5d5ae0f8891", + "shasum": "" + }, + "require": { + "illuminate/support": "^11.0 || ^12.0 || ^13.0", + "laravel/socialite": "^5.5", + "php": "^8.2" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "SocialiteProviders\\Manager\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "SocialiteProviders\\Manager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andy Wendt", + "email": "andy@awendt.com" + }, + { + "name": "Anton Komarev", + "email": "a.komarev@cybercog.su" + }, + { + "name": "Miguel Piedrafita", + "email": "soy@miguelpiedrafita.com" + }, + { + "name": "atymic", + "email": "atymicq@gmail.com", + "homepage": "https://atymic.dev" + } + ], + "description": "Easily add new or override built-in providers in Laravel Socialite.", + "homepage": "https://socialiteproviders.com", + "keywords": [ + "laravel", + "manager", + "oauth", + "providers", + "socialite" + ], + "support": { + "issues": "https://github.com/socialiteproviders/manager/issues", + "source": "https://github.com/socialiteproviders/manager" + }, + "time": "2026-03-18T22:13:24+00:00" + }, + { + "name": "socialiteproviders/nextcloud", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/SocialiteProviders/Nextcloud.git", + "reference": "94b3cef64410994bdd480230a7aa78294564cc44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SocialiteProviders/Nextcloud/zipball/94b3cef64410994bdd480230a7aa78294564cc44", + "reference": "94b3cef64410994bdd480230a7aa78294564cc44", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.2 || ^8.0", + "socialiteproviders/manager": "~4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "SocialiteProviders\\Nextcloud\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Artur Shaik", + "email": "artur@shaik.link" + } + ], + "description": "Nextcloud OAuth2 Provider for Laravel Socialite", + "support": { + "source": "https://github.com/SocialiteProviders/Nextcloud/tree/4.0.0" + }, + "time": "2021-02-27T23:17:54+00:00" + }, { "name": "spatie/color", "version": "1.8.0", @@ -6806,6 +7324,86 @@ ], "time": "2026-04-10T16:19:22+00:00" }, + { + "name": "symfony/polyfill-php82", + "version": "v1.38.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php82.git", + "reference": "002dc0cfe5fd4ed6033d48f27d4f19a486c4b04b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php82/zipball/002dc0cfe5fd4ed6033d48f27d4f19a486c4b04b", + "reference": "002dc0cfe5fd4ed6033d48f27d4f19a486c4b04b", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php82\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php82/tree/v1.38.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-05-26T12:45:58+00:00" + }, { "name": "symfony/polyfill-php83", "version": "v1.41.0", diff --git a/config/services.php b/config/services.php index 21ceac2..d2fdd85 100644 --- a/config/services.php +++ b/config/services.php @@ -35,6 +35,13 @@ return [ ], ], + 'nextcloud' => [ + 'client_id' => env('OAUTH_CLOUDSPICESBLUE_ID'), + 'client_secret' => env('OAUTH_CLOUDSPICESBLUE_SECRETKEY'), + 'redirect' => env('OAUTH_CLOUDSPICESBLUE_REDIRECTURI'), + 'base_url' => 'https://cloud.spices.blue', + ], + 'shopify' => [ 'domain' => env('SHOPIFY_SHOP_DOMAIN'), 'access_token' => env('SHOPIFY_ACCESS_TOKEN'), diff --git a/routes/web.php b/routes/web.php index 11fa2c8..b02e6a8 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,7 +1,11 @@ name('auth.nextcloud'); +Route::get('/oauth/callback', [OAuthController::class, 'callback'])->name('auth.nextcloud.callback');