From 7b5b15aebc9db7a96196f2b9b6529f8dd1e03ddd Mon Sep 17 00:00:00 2001 From: Erki Aas Date: Thu, 1 Feb 2024 15:20:10 +0200 Subject: [PATCH] Add OAuth module from repository --- Dockerfile | 3 +- modules/OAuth/Config/.gitkeep | 0 modules/OAuth/Config/config.php | 13 ++ modules/OAuth/Console/.gitkeep | 0 modules/OAuth/Database/Migrations/.gitkeep | 0 modules/OAuth/Database/Seeders/.gitkeep | 0 .../Database/Seeders/OAuthDatabaseSeeder.php | 21 ++ modules/OAuth/Database/factories/.gitkeep | 0 modules/OAuth/Entities/.gitkeep | 0 modules/OAuth/Http/Controllers/.gitkeep | 0 .../Http/Controllers/OAuthController.php | 60 ++++++ modules/OAuth/Http/Middleware/.gitkeep | 0 modules/OAuth/Http/Requests/.gitkeep | 0 modules/OAuth/Http/routes.php | 8 + modules/OAuth/Providers/.gitkeep | 0 .../OAuth/Providers/OAuthServiceProvider.php | 194 ++++++++++++++++++ modules/OAuth/Public/.gitkeep | 0 modules/OAuth/README.md | 32 +++ modules/OAuth/Resources/assets/.gitkeep | 0 modules/OAuth/Resources/lang/.gitkeep | 0 modules/OAuth/Resources/views/.gitkeep | 0 modules/OAuth/Resources/views/index.blade.php | 69 +++++++ .../Resources/views/layouts/master.blade.php | 12 ++ modules/OAuth/Tests/.gitkeep | 0 modules/OAuth/composer.json | 25 +++ modules/OAuth/module.json | 22 ++ modules/OAuth/start.php | 17 ++ 27 files changed, 474 insertions(+), 2 deletions(-) create mode 100755 modules/OAuth/Config/.gitkeep create mode 100755 modules/OAuth/Config/config.php create mode 100755 modules/OAuth/Console/.gitkeep create mode 100755 modules/OAuth/Database/Migrations/.gitkeep create mode 100755 modules/OAuth/Database/Seeders/.gitkeep create mode 100755 modules/OAuth/Database/Seeders/OAuthDatabaseSeeder.php create mode 100755 modules/OAuth/Database/factories/.gitkeep create mode 100755 modules/OAuth/Entities/.gitkeep create mode 100755 modules/OAuth/Http/Controllers/.gitkeep create mode 100755 modules/OAuth/Http/Controllers/OAuthController.php create mode 100755 modules/OAuth/Http/Middleware/.gitkeep create mode 100755 modules/OAuth/Http/Requests/.gitkeep create mode 100755 modules/OAuth/Http/routes.php create mode 100755 modules/OAuth/Providers/.gitkeep create mode 100755 modules/OAuth/Providers/OAuthServiceProvider.php create mode 100755 modules/OAuth/Public/.gitkeep create mode 100644 modules/OAuth/README.md create mode 100755 modules/OAuth/Resources/assets/.gitkeep create mode 100755 modules/OAuth/Resources/lang/.gitkeep create mode 100755 modules/OAuth/Resources/views/.gitkeep create mode 100755 modules/OAuth/Resources/views/index.blade.php create mode 100755 modules/OAuth/Resources/views/layouts/master.blade.php create mode 100755 modules/OAuth/Tests/.gitkeep create mode 100755 modules/OAuth/composer.json create mode 100755 modules/OAuth/module.json create mode 100755 modules/OAuth/start.php diff --git a/Dockerfile b/Dockerfile index e7faeb5..b926237 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,9 +53,8 @@ RUN echo d # Install freescout RUN git clone -b add-s3-support https://github.com/veebkolm/freescout.git /app - # Install oauth plugin -RUN git clone https://github.com/bolsunovskyi/freescout-oauth.git /app/Modules/OAuth +COPY modules/OAuth /app/Modules/OAuth # Install Composer dependencies RUN cd /app && composer install --no-dev && composer clear-cache diff --git a/modules/OAuth/Config/.gitkeep b/modules/OAuth/Config/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Config/config.php b/modules/OAuth/Config/config.php new file mode 100755 index 0000000..b31b630 --- /dev/null +++ b/modules/OAuth/Config/config.php @@ -0,0 +1,13 @@ + 'OAuth', + 'options' => [ + 'active' => ['default' => 'off'], + 'client_id' => ['default' => 'freescout'], + 'client_secret' => ['default' => ''], + 'auth_url' => ['default' => 'https://'], + 'token_url' => ['default' => 'https://'], + 'user_url' => ['default' => 'https://'] + ], +]; diff --git a/modules/OAuth/Console/.gitkeep b/modules/OAuth/Console/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Database/Migrations/.gitkeep b/modules/OAuth/Database/Migrations/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Database/Seeders/.gitkeep b/modules/OAuth/Database/Seeders/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Database/Seeders/OAuthDatabaseSeeder.php b/modules/OAuth/Database/Seeders/OAuthDatabaseSeeder.php new file mode 100755 index 0000000..015f311 --- /dev/null +++ b/modules/OAuth/Database/Seeders/OAuthDatabaseSeeder.php @@ -0,0 +1,21 @@ +call("OthersTableSeeder"); + } +} diff --git a/modules/OAuth/Database/factories/.gitkeep b/modules/OAuth/Database/factories/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Entities/.gitkeep b/modules/OAuth/Entities/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Http/Controllers/.gitkeep b/modules/OAuth/Http/Controllers/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Http/Controllers/OAuthController.php b/modules/OAuth/Http/Controllers/OAuthController.php new file mode 100755 index 0000000..cf0d8aa --- /dev/null +++ b/modules/OAuth/Http/Controllers/OAuthController.php @@ -0,0 +1,60 @@ + 1, + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => http_build_query([ + 'client_id' => $settings['oauth.client_id'], + 'client_secret'=> $settings['oauth.client_secret'], + 'grant_type' => 'authorization_code', + 'code' => $request->get('code'), + 'redirect_uri' => route('oauth_callback'), + ]), + CURLINFO_HEADER_OUT => true, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/x-www-form-urlencoded; charset=utf-8', + ], + ]); + $data = json_decode(curl_exec($ch), true); + $accessToken = $data['access_token']; + + curl_setopt_array($ch, [ + CURLOPT_URL => $settings['oauth.user_url'], + CURLOPT_HTTPHEADER => [ + 'Authorization: Bearer ' . $accessToken, + ], + ]); + $data = json_decode(curl_exec($ch), true); + + $user = User::where('email','=', $data['email'])->first(); + Auth::login($user); + + return redirect($request->session()->get('url.intended', '/')); + } +} diff --git a/modules/OAuth/Http/Middleware/.gitkeep b/modules/OAuth/Http/Middleware/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Http/Requests/.gitkeep b/modules/OAuth/Http/Requests/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Http/routes.php b/modules/OAuth/Http/routes.php new file mode 100755 index 0000000..4ef943d --- /dev/null +++ b/modules/OAuth/Http/routes.php @@ -0,0 +1,8 @@ + 'web', + 'prefix' => \Helper::getSubdirectory(), + 'namespace' => 'Modules\OAuth\Http\Controllers'], function() +{ + Route::get('/oauth_callback', 'OAuthController@index')->name('oauth_callback'); +}); diff --git a/modules/OAuth/Providers/.gitkeep b/modules/OAuth/Providers/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Providers/OAuthServiceProvider.php b/modules/OAuth/Providers/OAuthServiceProvider.php new file mode 100755 index 0000000..e4a2f13 --- /dev/null +++ b/modules/OAuth/Providers/OAuthServiceProvider.php @@ -0,0 +1,194 @@ +registerConfig(); + $this->registerViews(); + $this->registerFactories(); + $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + $this->hooks(); + } + + /** + * Module hooks. + */ + public function hooks() + { + \Eventy::addFilter('settings.sections', function($sections) { + $sections['oauth'] = ['title' => __('OAuth'), 'icon' => 'user', 'order' => 700]; + + return $sections; + }, 30); + + // Section settings + \Eventy::addFilter('settings.section_settings', function($settings, $section) { + + if ($section != 'oauth') { + return $settings; + } + + $settings = \Option::getOptions([ + 'oauth.active', + 'oauth.client_id', + 'oauth.client_secret', + 'oauth.auth_url', + 'oauth.token_url', + 'oauth.user_url', + ]); + + return $settings; + }, 20, 2); + + // Section parameters. + \Eventy::addFilter('settings.section_params', function($params, $section) { + if ($section != 'oauth') { + return $params; + } + + $params = [ + 'template_vars' => [], + 'validator_rules' => [], + ]; + + return $params; + }, 20, 2); + + // Settings view name + \Eventy::addFilter('settings.view', function($view, $section) { + if ($section != 'oauth') { + return $view; + } else { + return 'oauth::index'; + } + }, 20, 2); + + \Eventy::addFilter('middleware.web.custom_handle.response', function($prev, $rq, $next) { + $path = $rq->path(); + $loggedIn = Auth::check(); + + $settings = \Option::getOptions([ + 'oauth.active', + 'oauth.client_id', + 'oauth.auth_url', + ]); + + if (!$rq->get('disable_oauth', false) && $path == 'login' && !$loggedIn && + $settings['oauth.active'] == 'on') { + + $con = '?'; + if (strpos($settings['oauth.auth_url'], '?') !== false) { + $con = '&'; + } + + return redirect( + sprintf("%s%sclient_id=%s&response_type=code&redirect_uri=%s", + $settings['oauth.auth_url'], + $con, + $settings['oauth.client_id'], + route('oauth_callback') + ) + ); + } + + return $prev; + }, 10, 3); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->registerTranslations(); + } + + /** + * Register config. + * + * @return void + */ + protected function registerConfig() + { + $this->publishes([ + __DIR__.'/../Config/config.php' => config_path('oauth.php'), + ], 'config'); + $this->mergeConfigFrom( + __DIR__.'/../Config/config.php', 'oauth' + ); + } + + /** + * Register views. + * + * @return void + */ + public function registerViews() + { + $viewPath = resource_path('views/modules/oauth'); + + $sourcePath = __DIR__.'/../Resources/views'; + + $this->publishes([ + $sourcePath => $viewPath + ],'views'); + + $this->loadViewsFrom(array_merge(array_map(function ($path) { + return $path . '/modules/oauth'; + }, \Config::get('view.paths')), [$sourcePath]), 'oauth'); + } + + /** + * Register translations. + * + * @return void + */ + public function registerTranslations() + { + $this->loadJsonTranslationsFrom(__DIR__ .'/../Resources/lang'); + } + + /** + * Register an additional directory of factories. + * @source https://github.com/sebastiaanluca/laravel-resource-flow/blob/develop/src/Modules/ModuleServiceProvider.php#L66 + */ + public function registerFactories() + { + if (! app()->environment('production')) { + app(Factory::class)->load(__DIR__ . '/../Database/factories'); + } + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return []; + } +} diff --git a/modules/OAuth/Public/.gitkeep b/modules/OAuth/Public/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/README.md b/modules/OAuth/README.md new file mode 100644 index 0000000..753c2bc --- /dev/null +++ b/modules/OAuth/README.md @@ -0,0 +1,32 @@ +# OAuth FreeScout + +This module is intended to provide oauth authentication to freescout. + +Module was tested on keycloak oauth provider with confidential openid-connect client. + +Module is require php curl extension on server. + +Currently module fully replace login form with redirection to oauth provider login form. +If you need to perform ordinary login with basic form, add `disable_oauth` get parameter to login path (`/login?disable_oauth=1`) + +User must be registered before oauth login. + +## Installation + +- place module source to Modules folder of your FreeScout installation, module must have **OAuth** folder name to work propperly. If you are clonning repo with git, just add folder name in the end of git clone command. +- enable module in modules admin panel +- configure module on settings page (client id/secret/etc) + +## Provider Specific + +### Azure Active Directory (AAD) + +Register an App Registration in Azure Active Directory with scopes `openid`, `email` and `profile`. + +| Setting | Value | +| ------------------------------ | ------------------------------------------------------------------------------------------------ | +| **Client ID** | <_App Registration Client ID_> | +| **Client Secret** | <_App Registration Client secret_> | +| **Authorization Endpoint URL** | _https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize?scope=email+profile+openid_ | +| **Token Endpoint URL** | _https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token_ | +| **User Info Endpoint URL** | _https://graph.microsoft.com/oidc/userinfo_ | diff --git a/modules/OAuth/Resources/assets/.gitkeep b/modules/OAuth/Resources/assets/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Resources/lang/.gitkeep b/modules/OAuth/Resources/lang/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Resources/views/.gitkeep b/modules/OAuth/Resources/views/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/Resources/views/index.blade.php b/modules/OAuth/Resources/views/index.blade.php new file mode 100755 index 0000000..b74a926 --- /dev/null +++ b/modules/OAuth/Resources/views/index.blade.php @@ -0,0 +1,69 @@ +
+ {{ csrf_field() }} + +
+ + +
+ +
+
+ +
+ + +
+ + @include('partials/field_error', ['field'=>'settings.oauth.client_id']) +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+
+ + +
+ +
+
+ +
+ + {{ route('oauth_callback') }} +
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/modules/OAuth/Resources/views/layouts/master.blade.php b/modules/OAuth/Resources/views/layouts/master.blade.php new file mode 100755 index 0000000..c34e643 --- /dev/null +++ b/modules/OAuth/Resources/views/layouts/master.blade.php @@ -0,0 +1,12 @@ + + + + + + + Module OAuth + + + @yield('content') + + diff --git a/modules/OAuth/Tests/.gitkeep b/modules/OAuth/Tests/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/modules/OAuth/composer.json b/modules/OAuth/composer.json new file mode 100755 index 0000000..cd203ec --- /dev/null +++ b/modules/OAuth/composer.json @@ -0,0 +1,25 @@ +{ + "name": "freescout/oauth", + "description": "", + "authors": [ + { + "name": "Mike Bolsunovskyi", + "email": "mike@bolsunovskyi.com" + } + ], + "extra": { + "laravel": { + "providers": [ + "Modules\\OAuth\\Providers\\OAuthServiceProvider" + ], + "aliases": { + + } + } + }, + "autoload": { + "psr-4": { + "Modules\\OAuth\\": "" + } + } +} diff --git a/modules/OAuth/module.json b/modules/OAuth/module.json new file mode 100755 index 0000000..b074708 --- /dev/null +++ b/modules/OAuth/module.json @@ -0,0 +1,22 @@ +{ + "name": "OAuth", + "alias": "oauth", + "description": "", + "version": "1.0.0", + "detailsUrl": "", + "author": "", + "authorUrl": "", + "requiredAppVersion": "1.0.2", + "license": "AGPL-3.0", + "keywords": [], + "active": 0, + "order": 0, + "providers": [ + "Modules\\OAuth\\Providers\\OAuthServiceProvider" + ], + "aliases": {}, + "files": [ + "start.php" + ], + "requires": [] +} diff --git a/modules/OAuth/start.php b/modules/OAuth/start.php new file mode 100755 index 0000000..140a105 --- /dev/null +++ b/modules/OAuth/start.php @@ -0,0 +1,17 @@ +routesAreCached()) { + require __DIR__ . '/Http/routes.php'; +}