Hello community, here is the log from the commit of package yast2-rmt for openSUSE:Factory checked in at 2018-06-28 15:14:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/yast2-rmt (Old) and /work/SRC/openSUSE:Factory/.yast2-rmt.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "yast2-rmt" Thu Jun 28 15:14:21 2018 rev:6 rq:619421 version:1.0.1 Changes: -------- --- /work/SRC/openSUSE:Factory/yast2-rmt/yast2-rmt.changes 2018-05-19 15:43:02.937348524 +0200 +++ /work/SRC/openSUSE:Factory/.yast2-rmt.new/yast2-rmt.changes 2018-06-28 15:14:23.891485229 +0200 @@ -1,0 +2,7 @@ +Mon Jun 25 15:32:29 UTC 2018 - [email protected] + +- version 1.0.1 +- setting and validating CA private key password (bsc#1099324) +- reload nginx after configuration + +------------------------------------------------------------------- Old: ---- yast2-rmt-1.0.0.tar.bz2 New: ---- yast2-rmt-1.0.1.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ yast2-rmt.spec ++++++ --- /var/tmp/diff_new_pack.VFPMTj/_old 2018-06-28 15:14:25.331482591 +0200 +++ /var/tmp/diff_new_pack.VFPMTj/_new 2018-06-28 15:14:25.331482591 +0200 @@ -17,7 +17,7 @@ Name: yast2-rmt -Version: 1.0.0 +Version: 1.0.1 Release: 0 BuildArch: noarch ++++++ yast2-rmt-1.0.0.tar.bz2 -> yast2-rmt-1.0.1.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/README.md new/yast2-rmt-1.0.1/README.md --- old/yast2-rmt-1.0.0/README.md 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/README.md 2018-06-27 16:36:27.000000000 +0200 @@ -12,7 +12,7 @@ ### Running the module -`yast2-ruby-bindings` RPM package is not available as a gem, Yast runs on the system-wide Ruby interpreter only. +`yast2-ruby-bindings` RPM package is not available as a gem, YaST runs on the default system-wide Ruby interpreter only (available in the OSS repository). There different ways to run the module: @@ -41,7 +41,7 @@ rake osc:commit ``` -to commit the current version to OBS. +to commit the current version to OBS. #### Submit Requests to openSUSE Factory and SLES diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/package/yast2-rmt.changes new/yast2-rmt-1.0.1/package/yast2-rmt.changes --- old/yast2-rmt-1.0.0/package/yast2-rmt.changes 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/package/yast2-rmt.changes 2018-06-27 16:36:27.000000000 +0200 @@ -1,10 +1,18 @@ ------------------------------------------------------------------- +Mon Jun 25 15:32:29 UTC 2018 - [email protected] + +- version 1.0.1 +- setting and validating CA private key password (bsc#1099324) +- reload nginx after configuration + +------------------------------------------------------------------- Fri May 18 08:58:01 UTC 2018 - [email protected] - version 1.0.0 +- Release for SLES15 (bsc#1093879) - UI cleanups - Enable timers with rmt service start -- Add final configuration summary +- Add final configuration summary ------------------------------------------------------------------- Wed Apr 18 12:06:01 UTC 2018 - [email protected] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/package/yast2-rmt.spec new/yast2-rmt-1.0.1/package/yast2-rmt.spec --- old/yast2-rmt-1.0.0/package/yast2-rmt.spec 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/package/yast2-rmt.spec 2018-06-27 16:36:27.000000000 +0200 @@ -17,7 +17,7 @@ Name: yast2-rmt -Version: 1.0.0 +Version: 1.0.1 Release: 0 BuildArch: noarch diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/maria_db/current_root_password_dialog_spec.rb new/yast2-rmt-1.0.1/spec/rmt/maria_db/current_root_password_dialog_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/maria_db/current_root_password_dialog_spec.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/spec/rmt/maria_db/current_root_password_dialog_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -23,68 +23,15 @@ describe RMT::MariaDB::CurrentRootPasswordDialog do subject(:dialog) { described_class.new } - describe '#dialog_content' do - it 'creates the UI elements' do - expect(Yast::Term).to receive(:new).exactly(22).times - dialog.dialog_content - end - end - - describe '#user_input' do - it 'sets focus and waits for user input' do - expect(Yast::UI).to receive(:SetFocus).with(Id(:root_password)) - expect_any_instance_of(UI::Dialog).to receive(:user_input) - dialog.user_input - end - end - - describe '#ok_handler' do - context 'when the password field is empty' do - let(:password) { '' } - - it 'reports an error' do - expect(Yast::UI).to receive(:QueryWidget).with(Id(:root_password), :Value).and_return(password) - expect(Yast::UI).to receive(:SetFocus).with(Id(:root_password)) - expect(Yast::Report).to receive(:Error).with('Please provide the root password.') - expect(dialog).not_to receive(:finish_dialog) - dialog.ok_handler - end - end - - context 'when the password is invalid' do - let(:password) { 'password' } - - it 'reports an error' do - expect(Yast::UI).to receive(:QueryWidget).with(Id(:root_password), :Value).and_return(password) - expect(Yast::UI).to receive(:SetFocus).with(Id(:root_password)) - expect(dialog).to receive(:root_password_valid?).and_return(false) - expect(Yast::Report).to receive(:Error).with('The provided password is not valid.') - expect(dialog).not_to receive(:finish_dialog) - dialog.ok_handler - end - end - - context 'when the password is valid' do - let(:password) { 'password' } - - it 'finishes the dialog and returns the password' do - expect(Yast::UI).to receive(:QueryWidget).with(Id(:root_password), :Value).and_return(password) - expect(dialog).to receive(:root_password_valid?).and_return(true) - expect(dialog).to receive(:finish_dialog).with(password) - dialog.ok_handler - end - end - end - - describe '#root_password_valid?' do + describe '#password_valid?' do it 'returns true when exit code is 0' do expect(RMT::Utils).to receive(:run_command).and_return(0) - expect(dialog.root_password_valid?('password')).to be(true) + expect(dialog.send(:password_valid?, 'password')).to be(true) end it 'returns false when exit code is not 0' do expect(RMT::Utils).to receive(:run_command).and_return(1) - expect(dialog.root_password_valid?('password')).to be(false) + expect(dialog.send(:password_valid?, 'password')).to be(false) end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/maria_db/new_root_password_dialog_spec.rb new/yast2-rmt-1.0.1/spec/rmt/maria_db/new_root_password_dialog_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/maria_db/new_root_password_dialog_spec.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/spec/rmt/maria_db/new_root_password_dialog_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -23,64 +23,6 @@ describe RMT::MariaDB::NewRootPasswordDialog do subject(:dialog) { described_class.new } - describe '#dialog_content' do - it 'creates the UI elements' do - expect(Yast::Term).to receive(:new).exactly(26).times - dialog.dialog_content - end - end - - describe '#user_input' do - it 'sets focus and waits for user input' do - expect(Yast::UI).to receive(:SetFocus).with(Id(:new_root_password_1)) - expect_any_instance_of(UI::Dialog).to receive(:user_input) - dialog.user_input - end - end - - describe '#ok_handler' do - before do - expect(Yast::UI).to receive(:QueryWidget).with(Id(:new_root_password_1), :Value).and_return(password1) - expect(Yast::UI).to receive(:QueryWidget).with(Id(:new_root_password_2), :Value).and_return(password2) - end - - context 'when the password is blank' do - let(:password1) { '' } - let(:password2) { 'good_password' } - - it 'reports an error' do - expect(Yast::UI).to receive(:SetFocus).with(Id(:new_root_password_1)) - expect(Yast::Report).to receive(:Error).with('Password must not be blank.') - - expect(dialog).not_to receive(:finish_dialog) - dialog.ok_handler - end - end - - context 'when the password is blank' do - let(:password1) { 'bad_password' } - let(:password2) { 'good_password' } - - it 'reports an error' do - expect(Yast::UI).to receive(:SetFocus).with(Id(:new_root_password_2)) - expect(Yast::Report).to receive(:Error).with('The first and the second passwords do not match.') - - expect(dialog).not_to receive(:finish_dialog) - dialog.ok_handler - end - end - - context 'when the passwords match' do - let(:password1) { 'good_password' } - let(:password2) { 'good_password' } - - it 'finishes the dialog and returns the password' do - expect(dialog).to receive(:finish_dialog).with(password1) - dialog.ok_handler - end - end - end - describe '#set_root_password' do it 'returns true when exit code is 0' do expect(RMT::Utils).to receive(:run_command).and_return(0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/shared/input_password_dialog_spec.rb new/yast2-rmt-1.0.1/spec/rmt/shared/input_password_dialog_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/shared/input_password_dialog_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/spec/rmt/shared/input_password_dialog_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,84 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/shared/input_password_dialog' + +Yast.import 'Report' + +describe RMT::Shared::InputPasswordDialog do + subject(:dialog) { described_class.new } + + describe '#dialog_content' do + it 'creates the UI elements' do + expect(Yast::Term).to receive(:new).exactly(23).times + dialog.send(:dialog_content) + end + end + + describe '#user_input' do + it 'sets focus and waits for user input' do + expect(Yast::UI).to receive(:SetFocus).with(Id(:password)) + expect_any_instance_of(UI::Dialog).to receive(:user_input) + dialog.user_input + end + end + + describe '#ok_handler' do + context 'when the password field is empty' do + let(:password) { '' } + + it 'reports an error' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:password), :Value).and_return(password) + expect(Yast::UI).to receive(:SetFocus).with(Id(:password)) + expect(Yast::Report).to receive(:Error).with('Please provide the password.') + expect(dialog).not_to receive(:finish_dialog) + dialog.ok_handler + end + end + + context 'when the password is invalid' do + let(:password) { 'password' } + + it 'reports an error' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:password), :Value).and_return(password) + expect(Yast::UI).to receive(:SetFocus).with(Id(:password)) + expect(dialog).to receive(:password_valid?).and_return(false) + expect(Yast::Report).to receive(:Error).with('The provided password is not valid.') + expect(dialog).not_to receive(:finish_dialog) + dialog.ok_handler + end + end + + context 'when the password is valid' do + let(:password) { 'password' } + + it 'finishes the dialog and returns the password' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:password), :Value).and_return(password) + expect(dialog).to receive(:password_valid?).and_return(true) + expect(dialog).to receive(:finish_dialog).with(password) + dialog.ok_handler + end + end + end + + describe '#password_valid?' do + it 'raises error' do + expect { dialog.send(:password_valid?, 'password') }.to raise_error(NotImplementedError) + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/shared/set_password_dialog_spec.rb new/yast2-rmt-1.0.1/spec/rmt/shared/set_password_dialog_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/shared/set_password_dialog_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/spec/rmt/shared/set_password_dialog_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,97 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/shared/set_password_dialog' + +Yast.import 'Report' + +describe RMT::Shared::SetPasswordDialog do + subject(:dialog) { described_class.new } + + describe '#dialog_content' do + it 'creates the UI elements' do + expect(Yast::Term).to receive(:new).exactly(26).times + dialog.send(:dialog_content) + end + end + + describe '#user_input' do + it 'sets focus and waits for user input' do + expect(Yast::UI).to receive(:SetFocus).with(Id(:password)) + expect_any_instance_of(UI::Dialog).to receive(:user_input) + dialog.user_input + end + end + + describe '#ok_handler' do + before do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:password), :Value).and_return(password1) + expect(Yast::UI).to receive(:QueryWidget).with(Id(:password_confirmation), :Value).and_return(password2) + end + + context 'when the password is blank' do + let(:password1) { '' } + let(:password2) { 'good_password' } + + it 'reports an error' do + expect(Yast::UI).to receive(:SetFocus).with(Id(:password)) + expect(Yast::Report).to receive(:Error).with('Password must not be blank.') + + expect(dialog).not_to receive(:finish_dialog) + dialog.ok_handler + end + end + + context 'when the password too short' do + before { dialog.instance_variable_set(:@min_password_size, 4) } + let(:password1) { '12' } + let(:password2) { '12' } + + it 'reports an error' do + expect(Yast::UI).to receive(:SetFocus).with(Id(:password)) + expect(Yast::Report).to receive(:Error).with('Password has to have at least 4 characters.') + + expect(dialog).not_to receive(:finish_dialog) + dialog.ok_handler + end + end + + context 'when the password is blank' do + let(:password1) { 'bad_password' } + let(:password2) { 'good_password' } + + it 'reports an error' do + expect(Yast::UI).to receive(:SetFocus).with(Id(:password_confirmation)) + expect(Yast::Report).to receive(:Error).with('The first and the second passwords do not match.') + + expect(dialog).not_to receive(:finish_dialog) + dialog.ok_handler + end + end + + context 'when the passwords match' do + let(:password1) { 'good_password' } + let(:password2) { 'good_password' } + + it 'finishes the dialog and returns the password' do + expect(dialog).to receive(:finish_dialog).with(password1) + dialog.ok_handler + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/ssl/certificate_generator_spec.rb new/yast2-rmt-1.0.1/spec/rmt/ssl/certificate_generator_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/ssl/certificate_generator_spec.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/spec/rmt/ssl/certificate_generator_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -63,6 +63,41 @@ end end + describe '#ca_encrypted?' do + subject(:method_call) { generator.ca_encrypted? } + + it 'calls #valid_password? method' do + expect(generator).to receive(:valid_password?).with(' ') + method_call + end + end + + describe '#valid_password?' do + subject(:method_call) { generator.valid_password?(password) } + + let(:password) { 'foobar' } + + context 'with valid password' do + it 'returns true' do + expect(RMT::Execute).to receive(:on_target!).with( + 'openssl', 'rsa', '-passin', 'stdin', '-in', ssl_files[:ca_private_key], + stdin: password + ).and_return(true) + expect(method_call).to eq(true) + end + end + + context 'with invalid password' do + it 'returns false' do + expect(RMT::Execute).to receive(:on_target!).with( + 'openssl', 'rsa', '-passin', 'stdin', '-in', ssl_files[:ca_private_key], + stdin: password + ).and_raise(Cheetah::ExecutionFailed.new('', '', '', '')) + expect(method_call).to eq(false) + end + end + end + describe '#server_cert_present??' do subject(:result) { generator.server_cert_present? } @@ -104,6 +139,7 @@ let(:server_cert) { 'server_cert' } let(:common_name) { 'example.org' } let(:alt_names) { ['foo.example.org', 'bar.example.org'] } + let(:ca_password) { 'foobar' } context 'when CA is not yet generated' do it 'generates the CA and server certificates' do @@ -119,8 +155,9 @@ expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:server_config], server_config) expect(RMT::Execute).to receive(:on_target!).with( - 'openssl', 'genrsa', '-out', - ssl_files[:ca_private_key], described_class::OPENSSL_KEY_BITS + 'openssl', 'genrsa', '-aes256', '-passout', 'stdin', '-out', + ssl_files[:ca_private_key], described_class::OPENSSL_KEY_BITS, + stdin: ca_password ) expect(RMT::Execute).to receive(:on_target!).with( @@ -131,7 +168,50 @@ expect(RMT::Execute).to receive(:on_target!).with( 'openssl', 'req', '-x509', '-new', '-nodes', '-key', ssl_files[:ca_private_key], '-sha256', '-days', described_class::OPENSSL_CA_VALIDITY_DAYS, - '-out', ssl_files[:ca_certificate], '-config', ssl_files[:ca_config] + '-out', ssl_files[:ca_certificate], '-passin', 'stdin', '-config', ssl_files[:ca_config], + stdin: ca_password + ) + + expect(RMT::Execute).to receive(:on_target!).with( + 'openssl', 'req', '-new', '-key', ssl_files[:server_private_key], + '-out', ssl_files[:server_csr], '-config', ssl_files[:server_config] + ) + + expect(RMT::Execute).to receive(:on_target!).with( + 'openssl', 'x509', '-req', '-in', ssl_files[:server_csr], + '-out', ssl_files[:server_certificate], '-CA', ssl_files[:ca_certificate], + '-CAkey', ssl_files[:ca_private_key], '-passin', 'stdin', '-days', described_class::OPENSSL_SERVER_CERT_VALIDITY_DAYS, + '-sha256', '-CAcreateserial', '-extensions', 'v3_server_sign', + '-extfile', ssl_files[:server_config], + stdin: ca_password + ) + + expect(Yast::SCR).to receive(:Read).with(scr_path, ssl_files[:server_certificate]).and_return(server_cert) + expect(Yast::SCR).to receive(:Read).with(scr_path, ssl_files[:ca_certificate]).and_return(ca_cert) + expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:server_certificate], server_cert + ca_cert) + + expect(RMT::Execute).to receive(:on_target!).with('chown', 'root:nginx', ssl_files[:ca_certificate]) + expect(RMT::Execute).to receive(:on_target!).with('chmod', '0640', ssl_files[:ca_certificate]) + + generator.generate(common_name, alt_names, ca_password) + end + end + + context 'when CA is generated without password' do + let(:ca_password) { '' } + + it 'generates only the server certificate' do + expect(RMT::SSL::ConfigGenerator).to receive(:new).and_return(config_generator_double) + expect(generator).to receive(:ca_present?).and_return(true).exactly(2).times + expect(config_generator_double).to receive(:make_server_config).and_return(server_config) + + expect(generator).to receive(:create_files) + + expect(Yast::SCR).to receive(:Write).with(scr_path, ssl_files[:server_config], server_config) + + expect(RMT::Execute).to receive(:on_target!).with( + 'openssl', 'genrsa', '-out', + ssl_files[:server_private_key], described_class::OPENSSL_KEY_BITS ) expect(RMT::Execute).to receive(:on_target!).with( @@ -154,7 +234,7 @@ expect(RMT::Execute).to receive(:on_target!).with('chown', 'root:nginx', ssl_files[:ca_certificate]) expect(RMT::Execute).to receive(:on_target!).with('chmod', '0640', ssl_files[:ca_certificate]) - generator.generate(common_name, alt_names) + generator.generate(common_name, alt_names, ca_password) end end @@ -181,9 +261,10 @@ expect(RMT::Execute).to receive(:on_target!).with( 'openssl', 'x509', '-req', '-in', ssl_files[:server_csr], '-out', ssl_files[:server_certificate], '-CA', ssl_files[:ca_certificate], - '-CAkey', ssl_files[:ca_private_key], '-days', described_class::OPENSSL_SERVER_CERT_VALIDITY_DAYS, + '-CAkey', ssl_files[:ca_private_key], '-passin', 'stdin', '-days', described_class::OPENSSL_SERVER_CERT_VALIDITY_DAYS, '-sha256', '-CAcreateserial', '-extensions', 'v3_server_sign', - '-extfile', ssl_files[:server_config] + '-extfile', ssl_files[:server_config], + stdin: ca_password ) expect(Yast::SCR).to receive(:Read).with(scr_path, ssl_files[:server_certificate]).and_return(server_cert) @@ -193,20 +274,20 @@ expect(RMT::Execute).to receive(:on_target!).with('chown', 'root:nginx', ssl_files[:ca_certificate]) expect(RMT::Execute).to receive(:on_target!).with('chmod', '0640', ssl_files[:ca_certificate]) - generator.generate(common_name, alt_names) + generator.generate(common_name, alt_names, ca_password) end end it 'handles Cheetah::ExecutionFailed exceptions' do expect(RMT::SSL::ConfigGenerator).to receive(:new).and_raise(Cheetah::ExecutionFailed.new('cmd', 1, '', 'Dummy error')) expect(Yast::Report).to receive(:Error).with("An error occurred during SSL certificate generation:\nDummy error\n") - generator.generate(common_name, alt_names) + generator.generate(common_name, alt_names, ca_password) end it 'handles RMT::SSL::Exception exceptions' do expect(RMT::SSL::ConfigGenerator).to receive(:new).and_raise(RMT::SSL::Exception.new('Dummy error')) expect(Yast::Report).to receive(:Error).with("An error occurred during SSL certificate generation:\nDummy error\n") - generator.generate(common_name, alt_names) + generator.generate(common_name, alt_names, ca_password) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/ssl/current_ca_password_dialog_spec.rb new/yast2-rmt-1.0.1/spec/rmt/ssl/current_ca_password_dialog_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/ssl/current_ca_password_dialog_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/spec/rmt/ssl/current_ca_password_dialog_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,40 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/shared/input_password_dialog' +require 'rmt/ssl/current_ca_password_dialog' + +Yast.import 'Report' + +describe RMT::SSL::CurrentCaPasswordDialog do + subject(:dialog) { described_class.new } + + describe '#password_valid?' do + let(:password) { 'foobar' } + + it 'returns true when password is valid' do + expect_any_instance_of(RMT::SSL::CertificateGenerator).to receive(:valid_password?).with(password).and_return(true) + expect(dialog.send(:password_valid?, password)).to be(true) + end + + it 'returns false when exit code is not 0' do + expect_any_instance_of(RMT::SSL::CertificateGenerator).to receive(:valid_password?).with(password).and_return(false) + expect(dialog.send(:password_valid?, password)).to be(false) + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/ssl/new_ca_password_dialog_spec.rb new/yast2-rmt-1.0.1/spec/rmt/ssl/new_ca_password_dialog_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/ssl/new_ca_password_dialog_spec.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/spec/rmt/ssl/new_ca_password_dialog_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,34 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/ssl/new_ca_password_dialog' + +Yast.import 'Report' + +describe RMT::SSL::NewCaPasswordDialog do + subject(:dialog) { described_class.new } + + describe '#initialize' do + it 'creates the UI elements' do + expect(dialog.instance_variable_get(:@dialog_heading)).to eq('Setting CA private key password') + expect(dialog.instance_variable_get(:@dialog_label)).to eq('Please set new CA private key password') + expect(dialog.instance_variable_get(:@password_field_label)).to eq('New CA private key &Password') + expect(dialog.instance_variable_get(:@password_confirmation_field_label)).to eq('New Password &Again') + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/wizard_rmt_service_page_spec.rb new/yast2-rmt-1.0.1/spec/rmt/wizard_rmt_service_page_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/wizard_rmt_service_page_spec.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/spec/rmt/wizard_rmt_service_page_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -66,28 +66,50 @@ end describe '#run' do - context 'when service restart failed' do - it 'shows an error and continues' do - expect(service_page).to receive(:render_content) - expect(service_page).to receive(:rmt_service_start).and_return(false) - expect(Yast::Report).to receive(:Error).with("Failed to enable and restart service 'rmt-server'") - expect(Yast::Popup).to receive(:Feedback).and_call_original - expect(service_page).to receive(:event_loop) - service_page.run + context 'successful run' do + context 'restarting succeeds' do + it 'reloads and restarts the services and continues' do + expect(service_page).to receive(:render_content) + expect(Yast::Popup).to receive(:Feedback).and_call_original + expect(service_page).to receive(:rmt_service_start).and_return(true) + expect(Yast::Popup).to receive(:Feedback).and_call_original + expect(service_page).to receive(:nginx_service_reload).and_return(true) + expect(service_page).to receive(:event_loop) + service_page.run + end end end - context 'when service restart succeeded' do - it 'restarts rmt service and enters event loop' do - expect(service_page).to receive(:render_content) - expect(service_page).to receive(:rmt_service_start).and_return(true) - expect(Yast::Popup).to receive(:Feedback).and_call_original - expect(service_page).to receive(:event_loop) - service_page.run + context 'unsuccessful run' do + context 'restarting fails' do + it 'shows an error and continues' do + expect(service_page).to receive(:render_content) + expect(service_page).to receive(:rmt_service_start).and_return(false) + expect(Yast::Report).to receive(:Error).with('Failed to enable and restart RMT services and timers') + expect(service_page).to receive(:nginx_service_reload).and_return(false) + expect(Yast::Report).to receive(:Error).with("Failed to reload service for 'nginx'") + expect(service_page).to receive(:event_loop) + service_page.run + end end end end + describe '#nginx_service_reload' do + context 'succeeds to reload' do + it 'returns true' do + expect(Yast::Service).to receive(:Reload).with('nginx').and_return(true) + service_page.nginx_service_reload + end + end + + context 'fails to reload' do + it 'returns false' do + expect(Yast::Service).to receive(:Reload).with('nginx').and_return(false) + service_page.nginx_service_reload + end + end + end describe '#rmt_service_start' do context 'when restarting the service succeeds' do it 'shows confirmation' do diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/spec/rmt/wizard_ssl_page_spec.rb new/yast2-rmt-1.0.1/spec/rmt/wizard_ssl_page_spec.rb --- old/yast2-rmt-1.0.0/spec/rmt/wizard_ssl_page_spec.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/spec/rmt/wizard_ssl_page_spec.rb 2018-06-27 16:36:27.000000000 +0200 @@ -31,7 +31,7 @@ let(:alt_names) { %w[rmt-main.example.com rmt-01.example.com] } before do - expect(RMT::SSL::CertificateGenerator).to receive(:new).and_return(generator_double) + allow(RMT::SSL::CertificateGenerator).to receive(:new).and_return(generator_double) end describe '#render_content' do @@ -61,15 +61,72 @@ describe '#next_handler' do let(:common_name) { 'rmt.example.com' } let(:alt_names_items) { alt_names.map { |i| Yast::Term.new(:Item, i, i) } } + let(:current_ca_password_dialog_double) { instance_double(RMT::SSL::CurrentCaPasswordDialog) } + let(:new_ca_password_dialog_double) { instance_double(RMT::SSL::NewCaPasswordDialog) } + let(:ca_password) { 'foobar' } + + context 'with ca present' do + context 'with ca encrypted' do + it 'generates the certificates when next button is clicked' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:common_name), :Value).and_return(common_name) + expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_common_names), :Items).and_return(alt_names_items) + expect(generator_double).to receive(:ca_present?).and_return(true) + allow(generator_double).to receive(:ca_encrypted?).and_return(true) + + expect(RMT::SSL::CurrentCaPasswordDialog).to receive(:new).and_return(current_ca_password_dialog_double) + expect(current_ca_password_dialog_double).to receive(:run).and_return(ca_password) + expect(generator_double).to receive(:generate).with(common_name, alt_names, ca_password) + + expect(ssl_page).to receive(:finish_dialog).with(:next) + ssl_page.next_handler + end + end - it 'generates the certificates when next button is clicked' do - expect(Yast::UI).to receive(:QueryWidget).with(Id(:common_name), :Value).and_return(common_name) - expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_common_names), :Items).and_return(alt_names_items) + context 'with ca unencrypted' do + it 'generates the certificates when next button is clicked' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:common_name), :Value).and_return(common_name) + expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_common_names), :Items).and_return(alt_names_items) + expect(generator_double).to receive(:ca_present?).and_return(true) + allow(generator_double).to receive(:ca_encrypted?).and_return(false) + + expect(RMT::SSL::CurrentCaPasswordDialog).not_to receive(:new) + expect(generator_double).to receive(:generate).with(common_name, alt_names, '') + + expect(ssl_page).to receive(:finish_dialog).with(:next) + ssl_page.next_handler + end + end + end - expect(generator_double).to receive(:generate).with(common_name, alt_names) + context 'with ca empty' do + it 'generates the certificates when next button is clicked' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:common_name), :Value).and_return(common_name) + expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_common_names), :Items).and_return(alt_names_items) + + expect(generator_double).to receive(:ca_present?).and_return(false) + expect(RMT::SSL::NewCaPasswordDialog).to receive(:new).and_return(new_ca_password_dialog_double) + expect(new_ca_password_dialog_double).to receive(:run).and_return(ca_password) + expect(generator_double).to receive(:generate) - expect(ssl_page).to receive(:finish_dialog).with(:next) - ssl_page.next_handler + expect(ssl_page).to receive(:finish_dialog).with(:next) + ssl_page.next_handler + end + end + + context 'with no ca password' do + it 'does not generate certificate when ca_password is not provided' do + expect(Yast::UI).to receive(:QueryWidget).with(Id(:common_name), :Value).and_return(common_name) + expect(Yast::UI).to receive(:QueryWidget).with(Id(:alt_common_names), :Items).and_return(alt_names_items) + + expect(generator_double).to receive(:ca_present?).and_return(false) + expect(RMT::SSL::NewCaPasswordDialog).to receive(:new).and_return(new_ca_password_dialog_double) + expect(new_ca_password_dialog_double).to receive(:run).and_return(nil) + expect(generator_double).not_to receive(:generate) + expect(Yast::Popup).to receive(:Error).with('CA password not provided, skipping SSL keys generation.') + + expect(ssl_page).to receive(:finish_dialog).with(:next) + ssl_page.next_handler + end end end @@ -115,12 +172,29 @@ end describe '#run' do - context 'when certificates are already present' do - it 'shows a message and finishes' do - expect(generator_double).to receive(:server_cert_present?).and_return(true) - expect(Yast::Popup).to receive(:Message).with('SSL certificates already present, skipping generation.') - expect(ssl_page).to receive(:finish_dialog).with(:next) - ssl_page.run + context 'when server certificate is already present' do + context 'with encrypted' do + it 'shows proper error message' do + expect(generator_double).to receive(:server_cert_present?).and_return(true) + expect(generator_double).to receive(:ca_encrypted?).and_return(true) + expect(Yast::Popup).to receive(:Message).with( + 'SSL certificates already present, skipping generation.' + ) + expect(ssl_page).to receive(:finish_dialog).with(:next) + ssl_page.run + end + end + + context 'with non-encrypted' do + it 'shows a message and finishes' do + expect(generator_double).to receive(:server_cert_present?).and_return(true) + expect(generator_double).to receive(:ca_encrypted?).and_return(false) + expect(Yast::Popup).to receive(:Message).with( + "SSL certificates already present, skipping generation.\nPlease consider encrypting your CA private key!" + ) + expect(ssl_page).to receive(:finish_dialog).with(:next) + ssl_page.run + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/maria_db/current_root_password_dialog.rb new/yast2-rmt-1.0.1/src/lib/rmt/maria_db/current_root_password_dialog.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/maria_db/current_root_password_dialog.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/src/lib/rmt/maria_db/current_root_password_dialog.rb 2018-06-27 16:36:27.000000000 +0200 @@ -17,61 +17,24 @@ # you may find current contact information at www.suse.com require 'rmt/utils' +require 'rmt/shared/input_password_dialog' require 'ui/dialog' module RMT; end module RMT::MariaDB; end -class RMT::MariaDB::CurrentRootPasswordDialog < UI::Dialog +class RMT::MariaDB::CurrentRootPasswordDialog < RMT::Shared::InputPasswordDialog def initialize - textdomain 'rmt' - end - - def dialog_content - VBox( - VSpacing(1), - Heading(_('Database root password is required')), - VSpacing(1), - HBox( - HSpacing(2), - VBox( - Label(_('Please provide the current database root password.')), - MinWidth(15, Password(Id(:root_password), _('MariaDB root &password'))) - ), - HSpacing(2) - ), - VSpacing(1), - HBox( - PushButton(Id(:cancel), Opt(:key_F9), Yast::Label.CancelButton), - HSpacing(2), - PushButton(Id(:ok), Opt(:default, :key_F10), Yast::Label.OKButton) - ), - VSpacing(1) - ) - end - - def user_input - Yast::UI.SetFocus(Id(:root_password)) super - end - - def ok_handler - root_password = Yast::UI.QueryWidget(Id(:root_password), :Value) - if !root_password || root_password.empty? - Yast::UI.SetFocus(Id(:root_password)) - Yast::Report.Error(_('Please provide the root password.')) - return - elsif !root_password_valid?(root_password) - Yast::UI.SetFocus(Id(:root_password)) - Yast::Report.Error(_('The provided password is not valid.')) - return - end - - finish_dialog(root_password) + @dialog_heading = 'Database root password is required' + @dialog_label = 'Please provide the current database root password.' + @password_field_label = 'MariaDB root &password' end - def root_password_valid?(password) + private + + def password_valid?(password) RMT::Utils.run_command( "echo 'show databases;' | mysql -u root -p%1 2>/dev/null", password diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/maria_db/new_root_password_dialog.rb new/yast2-rmt-1.0.1/src/lib/rmt/maria_db/new_root_password_dialog.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/maria_db/new_root_password_dialog.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/src/lib/rmt/maria_db/new_root_password_dialog.rb 2018-06-27 16:36:27.000000000 +0200 @@ -17,66 +17,21 @@ # you may find current contact information at www.suse.com require 'rmt/utils' +require 'rmt/shared/set_password_dialog' require 'ui/dialog' module RMT; end module RMT::MariaDB; end -class RMT::MariaDB::NewRootPasswordDialog < UI::Dialog +class RMT::MariaDB::NewRootPasswordDialog < RMT::Shared::SetPasswordDialog def initialize - textdomain 'rmt' - end - - def dialog_content - VBox( - VSpacing(1), - Heading(_('Setting database root password')), - VSpacing(1), - HBox( - HSpacing(2), - VBox( - Label( - _( - "The current MariaDB root password is empty.\n" \ - 'Setting a root password is required for security reasons.' - ) - ), - VSpacing(1), - MinWidth(15, Password(Id(:new_root_password_1), _('New MariaDB root &Password'))), - MinWidth(15, Password(Id(:new_root_password_2), _('New Password &Again'))) - ), - HSpacing(2) - ), - VSpacing(1), - HBox( - PushButton(Id(:cancel), Opt(:key_F9), Yast::Label.CancelButton), - HSpacing(2), - PushButton(Id(:ok), Opt(:default, :key_F10), Yast::Label.OKButton) - ), - VSpacing(1) - ) - end - - def user_input - Yast::UI.SetFocus(Id(:new_root_password_1)) super - end - - def ok_handler - pass1 = Yast::UI.QueryWidget(Id(:new_root_password_1), :Value) - pass2 = Yast::UI.QueryWidget(Id(:new_root_password_2), :Value) - if pass1.nil? || pass1 == '' - Yast::UI.SetFocus(Id(:new_root_password_1)) - Yast::Report.Error(_('Password must not be blank.')) - return - elsif pass1 != pass2 - Yast::UI.SetFocus(Id(:new_root_password_2)) - Yast::Report.Error(_('The first and the second passwords do not match.')) - return - end - - finish_dialog(pass1) + @dialog_heading = 'Setting database root password' + @dialog_label = "The current MariaDB root password is empty.\n" \ + 'Setting a root password is required for security reasons.' + @password_field_label = 'New MariaDB root &Password' + @password_confirmation_field_label = 'New Password &Again' end def set_root_password(new_root_password, hostname) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/shared/input_password_dialog.rb new/yast2-rmt-1.0.1/src/lib/rmt/shared/input_password_dialog.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/shared/input_password_dialog.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/src/lib/rmt/shared/input_password_dialog.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,80 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/utils' +require 'ui/dialog' + +module RMT; end +module RMT::Shared; end + +class RMT::Shared::InputPasswordDialog < UI::Dialog + def initialize + textdomain 'rmt' + end + + def user_input + Yast::UI.SetFocus(Id(:password)) + super + end + + def ok_handler + password = Yast::UI.QueryWidget(Id(:password), :Value) + + if !password || password.empty? + Yast::UI.SetFocus(Id(:password)) + Yast::Report.Error(_('Please provide the password.')) + return + elsif !password_valid?(password) + Yast::UI.SetFocus(Id(:password)) + Yast::Report.Error(_('The provided password is not valid.')) + return + end + + finish_dialog(password) + end + + private + + def dialog_content + VBox( + VSpacing(1), + Heading(_(@dialog_heading)), + VSpacing(1), + HBox( + HSpacing(2), + VBox( + Label(_(@dialog_label)), + VSpacing(1), + MinWidth(15, Password(Id(:password), _(@password_field_label))) + ), + HSpacing(2) + ), + VSpacing(1), + HBox( + PushButton(Id(:cancel), Opt(:key_F9), Yast::Label.CancelButton), + HSpacing(2), + PushButton(Id(:ok), Opt(:default, :key_F10), Yast::Label.OKButton) + ), + VSpacing(1) + ) + end + + def password_valid?(_password) + raise NotImplementedError + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/shared/set_password_dialog.rb new/yast2-rmt-1.0.1/src/lib/rmt/shared/set_password_dialog.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/shared/set_password_dialog.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/src/lib/rmt/shared/set_password_dialog.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,87 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/utils' +require 'ui/dialog' + +module RMT; end +module RMT::Shared; end + +class RMT::Shared::SetPasswordDialog < UI::Dialog + def initialize + @min_password_size = 0 + textdomain 'rmt' + end + + def user_input + Yast::UI.SetFocus(Id(:password)) + super + end + + def ok_handler + password = Yast::UI.QueryWidget(Id(:password), :Value) + password_confirmation = Yast::UI.QueryWidget(Id(:password_confirmation), :Value) + + if password.nil? || password == '' + Yast::UI.SetFocus(Id(:password)) + Yast::Report.Error(_('Password must not be blank.')) + return + elsif password.size < @min_password_size + Yast::UI.SetFocus(Id(:password)) + Yast::Report.Error("Password has to have at least #{@min_password_size} characters.") + return + elsif password != password_confirmation + Yast::UI.SetFocus(Id(:password_confirmation)) + Yast::Report.Error(_('The first and the second passwords do not match.')) + return + end + + finish_dialog(password) + end + + private + + def dialog_content + VBox( + VSpacing(1), + Heading(_(@dialog_heading)), + VSpacing(1), + HBox( + HSpacing(2), + VBox( + Label( + _( + @dialog_label + ) + ), + VSpacing(1), + MinWidth(15, Password(Id(:password), _(@password_field_label))), + MinWidth(15, Password(Id(:password_confirmation), _(@password_confirmation_field_label))) + ), + HSpacing(2) + ), + VSpacing(1), + HBox( + PushButton(Id(:cancel), Opt(:key_F9), Yast::Label.CancelButton), + HSpacing(2), + PushButton(Id(:ok), Opt(:default, :key_F10), Yast::Label.OKButton) + ), + VSpacing(1) + ) + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/ssl/certificate_generator.rb new/yast2-rmt-1.0.1/src/lib/rmt/ssl/certificate_generator.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/ssl/certificate_generator.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/src/lib/rmt/ssl/certificate_generator.rb 2018-06-27 16:36:27.000000000 +0200 @@ -58,6 +58,20 @@ false end + def ca_encrypted? + !valid_password?(' ') # check with emtpy password. password has one char otherwise command requires input + end + + def valid_password?(password) + RMT::Execute.on_target!( + 'openssl', 'rsa', '-passin', 'stdin', '-in', @ssl_paths[:ca_private_key], + stdin: password + ) + true + rescue Cheetah::ExecutionFailed + false + end + def server_cert_present? # NB this doesn't check the second file if the first one exists # An improvement would be to look for the absence of any ssl configuration and proceed in that case, @@ -68,7 +82,8 @@ false end - def generate(common_name, alt_names) + # rubocop:disable Metrics/MethodLength + def generate(common_name, alt_names, ca_password) config_generator = RMT::SSL::ConfigGenerator.new(common_name, alt_names) files = @ssl_paths.dup @@ -77,16 +92,19 @@ create_files(files) Yast::SCR.Write(Yast.path('.target.string'), @ssl_paths[:server_config], config_generator.make_server_config) - unless ca_present? Yast::SCR.Write(Yast.path('.target.string'), @ssl_paths[:ca_serial_file], '01') Yast::SCR.Write(Yast.path('.target.string'), @ssl_paths[:ca_config], config_generator.make_ca_config) - RMT::Execute.on_target!('openssl', 'genrsa', '-out', @ssl_paths[:ca_private_key], OPENSSL_KEY_BITS) + RMT::Execute.on_target!( + 'openssl', 'genrsa', '-aes256', '-passout', 'stdin', '-out', @ssl_paths[:ca_private_key], OPENSSL_KEY_BITS, + stdin: ca_password + ) RMT::Execute.on_target!( 'openssl', 'req', '-x509', '-new', '-nodes', '-key', @ssl_paths[:ca_private_key], '-sha256', '-days', OPENSSL_CA_VALIDITY_DAYS, '-out', @ssl_paths[:ca_certificate], - '-config', @ssl_paths[:ca_config] + '-passin', 'stdin', '-config', @ssl_paths[:ca_config], + stdin: ca_password ) end @@ -96,13 +114,22 @@ '-out', @ssl_paths[:server_csr], '-config', @ssl_paths[:server_config] ) - RMT::Execute.on_target!( - 'openssl', 'x509', '-req', '-in', @ssl_paths[:server_csr], '-out', @ssl_paths[:server_certificate], - '-CA', @ssl_paths[:ca_certificate], '-CAkey', @ssl_paths[:ca_private_key], - '-days', OPENSSL_SERVER_CERT_VALIDITY_DAYS, '-sha256', - '-CAcreateserial', - '-extensions', 'v3_server_sign', '-extfile', @ssl_paths[:server_config] - ) + if !ca_password.empty? + RMT::Execute.on_target!( + 'openssl', 'x509', '-req', '-in', @ssl_paths[:server_csr], '-out', @ssl_paths[:server_certificate], + '-CA', @ssl_paths[:ca_certificate], '-CAkey', @ssl_paths[:ca_private_key], + '-passin', 'stdin', '-days', OPENSSL_SERVER_CERT_VALIDITY_DAYS, '-sha256', + '-CAcreateserial', '-extensions', 'v3_server_sign', '-extfile', @ssl_paths[:server_config], + stdin: ca_password + ) + else + RMT::Execute.on_target!( + 'openssl', 'x509', '-req', '-in', @ssl_paths[:server_csr], '-out', @ssl_paths[:server_certificate], + '-CA', @ssl_paths[:ca_certificate], '-CAkey', @ssl_paths[:ca_private_key], + '-days', OPENSSL_SERVER_CERT_VALIDITY_DAYS, '-sha256', + '-CAcreateserial', '-extensions', 'v3_server_sign', '-extfile', @ssl_paths[:server_config] + ) + end # create certificates bundle server_cert = Yast::SCR.Read(Yast.path('.target.string'), @ssl_paths[:server_certificate]) @@ -120,6 +147,7 @@ } ) end + # rubocop:enable Metrics/MethodLength protected diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/ssl/current_ca_password_dialog.rb new/yast2-rmt-1.0.1/src/lib/rmt/ssl/current_ca_password_dialog.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/ssl/current_ca_password_dialog.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/src/lib/rmt/ssl/current_ca_password_dialog.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,42 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/utils' +require 'rmt/ssl/certificate_generator' +require 'rmt/shared/input_password_dialog' +require 'ui/dialog' + +module RMT; end +module RMT::SSL; end + +class RMT::SSL::CurrentCaPasswordDialog < RMT::Shared::InputPasswordDialog + def initialize + super + + @dialog_heading = 'Your CA private key is encrypted.' + @dialog_label = 'Please input password.' + @password_field_label = '&Password' + @cert_generator = RMT::SSL::CertificateGenerator.new + end + + private + + def password_valid?(password) + @cert_generator.valid_password?(password) + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/ssl/new_ca_password_dialog.rb new/yast2-rmt-1.0.1/src/lib/rmt/ssl/new_ca_password_dialog.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/ssl/new_ca_password_dialog.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/yast2-rmt-1.0.1/src/lib/rmt/ssl/new_ca_password_dialog.rb 2018-06-27 16:36:27.000000000 +0200 @@ -0,0 +1,36 @@ +# Copyright (c) 2018 SUSE LLC. +# All Rights Reserved. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 or 3 of the GNU General +# Public License as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, contact SUSE LLC. + +# To contact SUSE about this file by physical or electronic mail, +# you may find current contact information at www.suse.com + +require 'rmt/utils' +require 'rmt/shared/set_password_dialog' +require 'ui/dialog' + +module RMT; end +module RMT::SSL; end + +class RMT::SSL::NewCaPasswordDialog < RMT::Shared::SetPasswordDialog + def initialize + super + + @dialog_heading = 'Setting CA private key password' + @dialog_label = 'Please set new CA private key password' + @password_field_label = 'New CA private key &Password' + @password_confirmation_field_label = 'New Password &Again' + @min_password_size = 4 + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/wizard_rmt_service_page.rb new/yast2-rmt-1.0.1/src/lib/rmt/wizard_rmt_service_page.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/wizard_rmt_service_page.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/src/lib/rmt/wizard_rmt_service_page.rb 2018-06-27 16:36:27.000000000 +0200 @@ -69,17 +69,33 @@ def run render_content - ok = false - Yast::Popup.Feedback(_('Starting services'), _('Starting RMT server, sync, and mirror timers...')) do - ok = rmt_service_start + rmt_services_started = false + nginx_service_reloaded = false + + Yast::Popup.Feedback(_('Starting RMT'), _('Starting RMT server, sync, and mirror timers ...')) do + rmt_services_started = rmt_service_start + end + unless rmt_services_started + UI.ChangeWidget(Id(:service_status), :Value, 'Could not start RMT services and timers.') + Yast::Report.Error(_('Failed to enable and restart RMT services and timers')) + end + + Yast::Popup.Feedback(_('Reloading nginx'), _('Reloading the nginx service ...')) do + nginx_service_reloaded = nginx_service_reload end - unless ok - UI.ChangeWidget(Id(:service_status), :Value, 'Could not start \'rmt-server\' service.') - Yast::Report.Error(_("Failed to enable and restart service 'rmt-server'")) + unless nginx_service_reloaded + UI.ChangeWidget(Id(:service_status), :Value, 'Could not reload \'nginx\' service.') + Yast::Report.Error(_('Failed to reload service for \'nginx\'')) end + event_loop end + def nginx_service_reload + return true if Yast::Service.Reload('nginx') + false + end + def rmt_service_start if Yast::Service.Enable('rmt-server') && Yast::Service.Restart('rmt-server') rmt_enable_timers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yast2-rmt-1.0.0/src/lib/rmt/wizard_ssl_page.rb new/yast2-rmt-1.0.1/src/lib/rmt/wizard_ssl_page.rb --- old/yast2-rmt-1.0.0/src/lib/rmt/wizard_ssl_page.rb 2018-05-18 13:57:35.000000000 +0200 +++ new/yast2-rmt-1.0.1/src/lib/rmt/wizard_ssl_page.rb 2018-06-27 16:36:27.000000000 +0200 @@ -17,6 +17,8 @@ # you may find current contact information at www.suse.com require 'rmt/ssl/alternative_common_name_dialog' +require 'rmt/ssl/current_ca_password_dialog' +require 'rmt/ssl/new_ca_password_dialog' require 'rmt/ssl/config_generator' require 'rmt/ssl/certificate_generator' require 'rmt/execute' @@ -87,7 +89,21 @@ alt_names_items = UI.QueryWidget(Id(:alt_common_names), :Items) alt_names = alt_names_items.map { |item| item.params[1] } - @cert_generator.generate(common_name, alt_names) + ca_password = if @cert_generator.ca_present? + if @cert_generator.ca_encrypted? + RMT::SSL::CurrentCaPasswordDialog.new.run + else + '' # use empty password + end + else + RMT::SSL::NewCaPasswordDialog.new.run + end + + if ca_password + @cert_generator.generate(common_name, alt_names, ca_password) + else + Report.Error(_('CA password not provided, skipping SSL keys generation.')) + end finish_dialog(:next) end @@ -117,7 +133,13 @@ def run if @cert_generator.server_cert_present? - Yast::Popup.Message(_('SSL certificates already present, skipping generation.')) + if @cert_generator.ca_encrypted? + Yast::Popup.Message(_('SSL certificates already present, skipping generation.')) + else + Yast::Popup.Message(_("SSL certificates already present, skipping generation.\n" \ + 'Please consider encrypting your CA private key!')) + end + return finish_dialog(:next) end render_content
