From b6a687934ddd36103155494a1eb12a196fc11c94 Mon Sep 17 00:00:00 2001 From: Kosh <koshatul@users.noreply.github.com> Date: Tue, 24 Sep 2019 15:08:48 +1000 Subject: [PATCH 1/5] changed split on whitespace to split on tab --- lib/puppet/provider/mysql_user/mysql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index 7d8f43c68..37ef661ff 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -24,7 +24,7 @@ def self.instances end @max_user_connections, @max_connections_per_hour, @max_queries_per_hour, @max_updates_per_hour, ssl_type, ssl_cipher, x509_issuer, x509_subject, - @password, @plugin = mysql_caller(query, 'regular').split(%r{\s}) + @password, @plugin = mysql_caller(query, 'regular').split(%r{\t}) @tls_options = parse_tls_options(ssl_type, ssl_cipher, x509_issuer, x509_subject) # rubocop:enable Metrics/LineLength new(name: name, From 7feb8354bc73e4c3f0dbd4430279e6b39072c000 Mon Sep 17 00:00:00 2001 From: Daniel Carabas <daniel.carabas@puppet.com> Date: Thu, 13 Feb 2020 15:38:51 +0200 Subject: [PATCH 2/5] Fix unit test mocking for tab separation --- spec/unit/puppet/provider/mysql_user/mysql_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index 61af6f8c3..4c34a6ad7 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -89,7 +89,7 @@ Puppet::Util.stubs(:which).with('mysqld').returns('/usr/sbin/mysqld') File.stubs(:file?).with('/root/.my.cnf').returns(true) provider.class.stubs(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').returns('joe@localhost') - provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'regular').returns('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') # rubocop:disable Metrics/LineLength + provider.class.stubs(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'regular').returns('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') # rubocop:disable Metrics/LineLength end describe 'self.instances' do From 9b767183e7b78017b97287cadf772de77119830c Mon Sep 17 00:00:00 2001 From: Kosh <koshatul@users.noreply.github.com> Date: Tue, 2 Jun 2020 17:22:49 +1000 Subject: [PATCH 3/5] strip trailing newline on mysql_caller return --- lib/puppet/provider/mysql_user/mysql.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index befb9571e..58be686ae 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -23,7 +23,7 @@ def self.instances end @max_user_connections, @max_connections_per_hour, @max_queries_per_hour, @max_updates_per_hour, ssl_type, ssl_cipher, x509_issuer, x509_subject, - @password, @plugin, @authentication_string = mysql_caller(query, 'regular').split(%r{\t}) + @password, @plugin, @authentication_string = mysql_caller(query, 'regular').chomp.split(%r{\t}) @tls_options = parse_tls_options(ssl_type, ssl_cipher, x509_issuer, x509_subject) if newer_than('mariadb' => '10.1.21') && @plugin == 'ed25519' # Some auth plugins (e.g. ed25519) use authentication_string From 89d96bc97420ff4d4d032689a64629da9a347d03 Mon Sep 17 00:00:00 2001 From: Kosh <koshatul@users.noreply.github.com> Date: Wed, 3 Jun 2020 10:04:46 +1000 Subject: [PATCH 4/5] updated tls_options return to match MySQL documentation, added spec and acceptance tests --- lib/puppet/provider/mysql_user/mysql.rb | 6 +-- spec/acceptance/types/mysql_user_spec.rb | 54 +++++++++++++++++++ .../puppet/provider/mysql_user/mysql_spec.rb | 38 +++++++++++++ 3 files changed, 95 insertions(+), 3 deletions(-) diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index 58be686ae..eafc71492 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -244,9 +244,9 @@ def self.parse_tls_options(ssl_type, ssl_cipher, x509_issuer, x509_subject) ['X509'] elsif ssl_type == 'SPECIFIED' options = [] - options << "CIPHER #{ssl_cipher}" if !ssl_cipher.nil? && !ssl_cipher.empty? - options << "ISSUER #{x509_issuer}" if !x509_issuer.nil? && !x509_issuer.empty? - options << "SUBJECT #{x509_subject}" if !x509_subject.nil? && !x509_subject.empty? + options << "CIPHER '#{ssl_cipher}'" if !ssl_cipher.nil? && !ssl_cipher.empty? + options << "ISSUER '#{x509_issuer}'" if !x509_issuer.nil? && !x509_issuer.empty? + options << "SUBJECT '#{x509_subject}'" if !x509_subject.nil? && !x509_subject.empty? options else ['NONE'] diff --git a/spec/acceptance/types/mysql_user_spec.rb b/spec/acceptance/types/mysql_user_spec.rb index 88eb79833..cd75d31cc 100644 --- a/spec/acceptance/types/mysql_user_spec.rb +++ b/spec/acceptance/types/mysql_user_spec.rb @@ -199,4 +199,58 @@ class { 'mysql::server': * => $ed25519_opts } end end end + context 'using user-w-subject@localhost with ISSUER and SUBJECT' do + describe 'adding user' do + pp_six = <<-MANIFEST + mysql_user { 'user-w-subject@localhost': + plugin => 'mysql_native_password', + password_hash => '', + tls_options => [ + "SUBJECT '/OU=MySQL Users/CN=username'", + "ISSUER '/CN=Certificate Authority'", + "CIPHER 'EDH-RSA-DES-CBC3-SHA'", + ], + } + MANIFEST + + it 'works without errors' do + idempotent_apply(pp_six) + end + + it 'finds the user #stdout' do + run_shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'user-w-subject@localhost'\"") do |r| + expect(r.stdout).to match(%r{^1$}) + expect(r.stderr).to be_empty + end + end + + it 'shows correct ssl_type #stdout' do + run_shell("mysql -NBe \"select SSL_TYPE from mysql.user where CONCAT(user, '@', host) = 'user-w-subject@localhost'\"") do |r| + expect(r.stdout).to match(%r{^SPECIFIED$}) + expect(r.stderr).to be_empty + end + end + + it 'shows correct x509_issuer #stdout' do + run_shell("mysql -NBe \"select X509_ISSUER from mysql.user where CONCAT(user, '@', host) = 'user-w-subject@localhost'\"") do |r| + expect(r.stdout).to match(%r{^/CN=Certificate Authority$}) + expect(r.stderr).to be_empty + end + end + + it 'shows correct x509_subject #stdout' do + run_shell("mysql -NBe \"select X509_SUBJECT from mysql.user where CONCAT(user, '@', host) = 'user-w-subject@localhost'\"") do |r| + expect(r.stdout).to match(%r{^/OU=MySQL Users/CN=username$}) + expect(r.stderr).to be_empty + end + end + + it 'shows correct ssl_cipher #stdout' do + run_shell("mysql -NBe \"select SSL_CIPHER from mysql.user where CONCAT(user, '@', host) = 'user-w-subject@localhost'\"") do |r| + expect(r.stdout).to match(%r{^EDH-RSA-DES-CBC3-SHA$}) + expect(r.stderr).to be_empty + end + end + end + end end diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index 5f5f6b3c9..5c8d1dc0a 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -439,6 +439,44 @@ end end + describe 'tls_options=required' do + it 'adds mTLS option grant in mysql 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.5'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE ISSUER '/CN=Certificate Authority' AND SUBJECT '/OU=MySQL Users/CN=Username'", 'system').returns('0') + + provider.expects(:tls_options).returns(['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\'']) + provider.tls_options = ['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\''] + end + it 'adds mTLS option grant in mysql 5.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.6'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE ISSUER '/CN=Certificate Authority' AND SUBJECT '/OU=MySQL Users/CN=Username'", 'system').returns('0') + + provider.expects(:tls_options).returns(['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\'']) + provider.tls_options = ['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\''] + end + it 'adds mTLS option grant in mysql < 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE ISSUER '/CN=Certificate Authority' AND SUBJECT '/OU=MySQL Users/CN=Username'", 'system').returns('0') + + provider.expects(:tls_options).returns(['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\'']) + provider.tls_options = ['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\''] + end + it 'adds mTLS option grant in mysql >= 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.expects(:mysql_caller).with("ALTER USER 'joe'@'localhost' REQUIRE ISSUER '/CN=Certificate Authority' AND SUBJECT '/OU=MySQL Users/CN=Username'", 'system').returns('0') + + provider.expects(:tls_options).returns(['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\'']) + provider.tls_options = ['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\''] + end + it 'adds mTLS option grant in mariadb-10.0' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.0'][:string]) + provider.class.expects(:mysql_caller).with("GRANT USAGE ON *.* TO 'joe'@'localhost' REQUIRE ISSUER '/CN=Certificate Authority' AND SUBJECT '/OU=MySQL Users/CN=Username'", 'system').returns('0') + + provider.expects(:tls_options).returns(['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\'']) + provider.tls_options = ['ISSUER \'/CN=Certificate Authority\'', 'SUBJECT \'/OU=MySQL Users/CN=Username\''] + end + end + ['max_user_connections', 'max_connections_per_hour', 'max_queries_per_hour', 'max_updates_per_hour'].each do |property| describe property do it "returns #{property}" do From 698c21ce1fe4b66dd25fbdac40d5398636a3bb0d Mon Sep 17 00:00:00 2001 From: Kosh <koshatul@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:33:55 +1000 Subject: [PATCH 5/5] fix for litmus acceptance failures --- spec/acceptance/types/mysql_user_spec.rb | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/spec/acceptance/types/mysql_user_spec.rb b/spec/acceptance/types/mysql_user_spec.rb index cd75d31cc..8129a8908 100644 --- a/spec/acceptance/types/mysql_user_spec.rb +++ b/spec/acceptance/types/mysql_user_spec.rb @@ -201,20 +201,17 @@ class { 'mysql::server': * => $ed25519_opts } end context 'using user-w-subject@localhost with ISSUER and SUBJECT' do describe 'adding user' do - pp_six = <<-MANIFEST - mysql_user { 'user-w-subject@localhost': - plugin => 'mysql_native_password', - password_hash => '', - tls_options => [ - "SUBJECT '/OU=MySQL Users/CN=username'", - "ISSUER '/CN=Certificate Authority'", - "CIPHER 'EDH-RSA-DES-CBC3-SHA'", - ], - } - MANIFEST - it 'works without errors' do - idempotent_apply(pp_six) + pp = <<-MANIFEST + mysql_user { 'user-w-subject@localhost': + tls_options => [ + "SUBJECT '/OU=MySQL Users/CN=username'", + "ISSUER '/CN=Certificate Authority'", + "CIPHER 'EDH-RSA-DES-CBC3-SHA'", + ], + } + MANIFEST + idempotent_apply(pp) end it 'finds the user #stdout' do