From 4f5374b2e8f713d604a6932b1ba7b5452ae705e6 Mon Sep 17 00:00:00 2001 From: Michael Pietsch Date: Fri, 14 Aug 2020 11:10:19 +0200 Subject: [PATCH] enable use custom file based saml certificate/private key --- app/Http/Controllers/SettingsController.php | 7 +- app/Http/Requests/SettingsSamlRequest.php | 84 ++++++++++++++----- app/Services/Saml.php | 9 +- ...020_08_11_200712_add_saml_key_rollover.php | 32 +++++++ resources/views/settings/saml.blade.php | 4 +- 5 files changed, 113 insertions(+), 23 deletions(-) create mode 100644 database/migrations/2020_08_11_200712_add_saml_key_rollover.php diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 53dae7c849..b242527144 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -1043,6 +1043,11 @@ class SettingsController extends Controller $setting->saml_sp_x509cert = $request->input('saml_sp_x509cert'); $setting->saml_sp_privatekey = $request->input('saml_sp_privatekey'); } + if (!empty($request->input('saml_sp_x509certNew'))) { + $setting->saml_sp_x509certNew = $request->input('saml_sp_x509certNew'); + } else { + $setting->saml_sp_x509certNew = ""; + } $setting->saml_custom_settings = $request->input('saml_custom_settings'); if ($setting->save()) { @@ -1257,4 +1262,4 @@ class SettingsController extends Controller { return view('settings.logins'); } -} \ No newline at end of file +} diff --git a/app/Http/Requests/SettingsSamlRequest.php b/app/Http/Requests/SettingsSamlRequest.php index f8629a2b4d..b5eeac17f6 100644 --- a/app/Http/Requests/SettingsSamlRequest.php +++ b/app/Http/Requests/SettingsSamlRequest.php @@ -5,11 +5,13 @@ namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; use OneLogin\Saml2\IdPMetadataParser as OneLogin_Saml2_IdPMetadataParser; use OneLogin\Saml2\Utils as OneLogin_Saml2_Utils; +use App\Models\Setting; /** * This handles validating and cleaning SAML settings provided by the user. * * @author Johnson Yi + * @author Michael Pietsch * * @since 5.0.0 */ @@ -55,7 +57,49 @@ class SettingsSamlRequest extends FormRequest } } - if ($this->input('saml_sp_regenerate_keypair') == '1' || !$this->has('saml_sp_x509cert')) { + $was_custom_x509cert = strpos(Setting::getSettings()->saml_custom_settings, 'sp_x509cert') !== false; + + $custom_x509cert=''; + $custom_privateKey=''; + $custom_x509certNew=''; + if (!empty($this->input('saml_custom_settings'))) { + $req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings')); + $custom_settings = []; + + foreach ($req_custom_settings as $custom_setting) { + $split = explode('=', $custom_setting, 2); + + if (count($split) == 2) { + $split[0] = trim($split[0]); + $split[1] = trim($split[1]); + + if (!empty($split[0])) { + $custom_settings[] = implode('=', $split); + } + if ($split[0] == 'sp_x509cert') { + $custom_x509cert = $split[1]; + } elseif ($split[0] == 'sp_privateKey') { + $custom_privateKey = $split[1]; + } elseif ($split[0] == 'sp_x509certNew') { + //to prepare for Key rollover + $custom_x509certNew = $split[1]; + } + } + } + + $this->merge(['saml_custom_settings' => implode(PHP_EOL, $custom_settings) . PHP_EOL]); + } + + $cert_updated=false; + if (!empty($custom_x509cert) && !empty($custom_privateKey)) { + // custom certificate and private key are defined + $cert_updated=true; + $x509 = openssl_x509_read($custom_x509cert); + $pkey = openssl_pkey_get_private($custom_privateKey); + } elseif ($this->input('saml_sp_regenerate_keypair') == '1' || !$this->has('saml_sp_x509cert') || $was_custom_x509cert) { + // key regeneration requested, no certificate defined yet or previous custom certicate was removed +error_log("regen"); + $cert_updated=true; $dn = [ "countryName" => "US", "stateOrProvinceName" => "N/A", @@ -72,11 +116,14 @@ class SettingsSamlRequest extends FormRequest $csr = openssl_csr_new($dn, $pkey, ['digest_alg' => 'sha256']); $x509 = openssl_csr_sign($csr, null, $pkey, 3650, ['digest_alg' => 'sha256']); + } + $errors = []; + + if ($cert_updated) { openssl_x509_export($x509, $x509cert); openssl_pkey_export($pkey, $privateKey); - $errors = []; while (($error = openssl_error_string() !== false)) { $errors[] = $error; } @@ -89,24 +136,23 @@ class SettingsSamlRequest extends FormRequest } } - if (!empty($this->input('saml_custom_settings'))) { - $req_custom_settings = preg_split('/\r\n|\r|\n/', $this->input('saml_custom_settings')); - $custom_settings = []; - - foreach ($req_custom_settings as $custom_setting) { - $split = explode('=', $custom_setting, 2); - - if (count($split) == 2) { - $split[0] = trim($split[0]); - $split[1] = trim($split[1]); - - if (!empty($split[0])) { - $custom_settings[] = implode('=', $split); - } - } + if ($custom_x509certNew) { + $x509New = openssl_x509_read($custom_x509certNew); + openssl_x509_export($x509New, $x509certNew); + + while (($error = openssl_error_string() !== false)) { + $errors[] = $error; } - - $this->merge(['saml_custom_settings' => implode(PHP_EOL, $custom_settings) . PHP_EOL]); + + if (!empty($x509certNew)) { + $this->merge([ + 'saml_sp_x509certNew' => $x509certNew + ]); + } + } else { + $this->merge([ + 'saml_sp_x509certNew' => "" + ]); } }); } diff --git a/app/Services/Saml.php b/app/Services/Saml.php index 0c321f6457..981449b0ae 100644 --- a/app/Services/Saml.php +++ b/app/Services/Saml.php @@ -140,6 +140,7 @@ class Saml * Builds settings from Snipe-IT for OneLogin_Saml2_Auth. * * @author Johnson Yi + * @author Michael Pietsch * * @since 5.0.0 * @@ -158,6 +159,11 @@ class Saml data_set($settings, 'sp.singleLogoutService.url', route('saml.sls')); data_set($settings, 'sp.x509cert', $setting->saml_sp_x509cert); data_set($settings, 'sp.privateKey', $setting->saml_sp_privatekey); + if(!empty($setting->saml_sp_x509certNew)) { + data_set($settings, 'sp.x509certNew', $setting->saml_sp_x509certNew); + } else { + data_set($settings, 'sp.x509certNew', ""); + } if (!empty(data_get($settings, 'sp.privateKey'))) { data_set($settings, 'security.logoutRequestSigned', true); @@ -210,7 +216,6 @@ class Saml } } } - $this->_settings = $settings; } } @@ -484,4 +489,4 @@ class Saml return $username; } -} \ No newline at end of file +} diff --git a/database/migrations/2020_08_11_200712_add_saml_key_rollover.php b/database/migrations/2020_08_11_200712_add_saml_key_rollover.php new file mode 100644 index 0000000000..42a3e24dcd --- /dev/null +++ b/database/migrations/2020_08_11_200712_add_saml_key_rollover.php @@ -0,0 +1,32 @@ +text('saml_sp_x509certNew')->nullable()->default(NULL); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function(Blueprint $table) { + $table->dropColumn('saml_sp_x509certNew'); + }); + } +} diff --git a/resources/views/settings/saml.blade.php b/resources/views/settings/saml.blade.php index b5550d30f3..a157b8b2f0 100644 --- a/resources/views/settings/saml.blade.php +++ b/resources/views/settings/saml.blade.php @@ -145,7 +145,9 @@ {{ Form::label('saml_custom_settings', trans('admin/settings/general.saml_custom_settings')) }}
- {{ Form::textarea('saml_custom_settings', old('saml_custom_settings', $setting->saml_custom_settings), ['class' => 'form-control','placeholder' => 'example.option=false', 'wrap' => 'off', $setting->demoMode]) }} + {{ Form::textarea('saml_custom_settings', old('saml_custom_settings', $setting->saml_custom_settings), ['class' => 'form-control','placeholder' => 'example.option=false +sp_x509cert=file:///... +sp_private_key=file:///', 'wrap' => 'off', $setting->demoMode]) }}

{{ trans('admin/settings/general.saml_custom_settings_help') }}

{!! $errors->first('saml_custom_settings', '') !!}