diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 83eb7ae22f..02a0f2c47c 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -998,6 +998,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()) { @@ -1226,4 +1231,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 ece772c5cd..74cdaf39da 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", @@ -94,24 +138,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 fa2eb13105..9b0204bbce 100644 --- a/app/Services/Saml.php +++ b/app/Services/Saml.php @@ -141,6 +141,7 @@ class Saml * Builds settings from Snipe-IT for OneLogin_Saml2_Auth. * * @author Johnson Yi + * @author Michael Pietsch * * @since 5.0.0 * @@ -162,6 +163,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); @@ -214,7 +220,6 @@ class Saml } } } - $this->_settings = $settings; } } @@ -502,4 +507,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 adddf700fd..55d79e0c7e 100644 --- a/resources/views/settings/saml.blade.php +++ b/resources/views/settings/saml.blade.php @@ -157,7 +157,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', '') !!}