diff --git a/lib/puppet/functions/mysql/password.rb b/lib/puppet/functions/mysql/password.rb index c25778a14..877fc6faa 100644 --- a/lib/puppet/functions/mysql/password.rb +++ b/lib/puppet/functions/mysql/password.rb @@ -22,7 +22,8 @@ def password(password, sensitive = false) password = password.unwrap if password.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive) - result_string = if %r{^\*[A-F0-9]{40}$}.match?(password) + # This magic string is the hex encoded form of `$A$005${SALT}{SHA DIGEST}`, matching MySQL's expected format + result_string = if %r{\*[A-F0-9]{40}$}.match?(password) || %r{0x24412430303524[A-F0-9]{63}$}.match?(password) password elsif password.empty? '' diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index b552a5620..81ef9e954 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -24,6 +24,13 @@ def self.instances # rubocop:enable Layout/LineLength @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').chomp.split(%r{\t}) + + if @plugin == 'caching_sha2_password' + # Escaping all single quotes to prevent errors when password generated it + @password = @password.gsub("'") { "\\'" } + @password = mysql_caller("SELECT CONCAT('0x',HEX('#{@password}'))", 'regular').chomp + end + @tls_options = parse_tls_options(ssl_type, ssl_cipher, x509_issuer, x509_subject) if (newer_than('mariadb' => '10.1.21') && (@plugin == 'ed25519' || @plugin == 'mysql_native_password')) || (newer_than('mariadb' => '10.2.16') && older_than('mariadb' => '10.2.19')) || @@ -77,6 +84,8 @@ def create if !plugin.nil? if password_hash.nil? self.class.mysql_caller("CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}'", 'system') + elsif plugin.eql? 'caching_sha2_password' + self.class.mysql_caller("CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}' AS X'#{password_hash[2..-1]}'", 'system') else self.class.mysql_caller("CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}' AS '#{password_hash}'", 'system') end @@ -160,9 +169,16 @@ def password_hash=(string) end self.class.mysql_caller(sql, 'system') elsif !mysqld_version.nil? && newer_than('mysql' => '5.7.6', 'percona' => '5.7.6', 'mariadb' => '10.2.0') - raise ArgumentError, _('Only mysql_native_password (*ABCD...XXX) hashes are supported.') unless %r{^\*|^$}.match?(string) + raise ArgumentError, _('Only mysql_native_password (*ABCD...XXX) or caching_sha2_password (0x1234ABC...XXX) hashes are supported.') unless + %r{^\*|^$}.match?(string) || %r{0x[A-F0-9]+$}.match?(string) - self.class.mysql_caller("ALTER USER #{merged_name} IDENTIFIED WITH mysql_native_password AS '#{string}'", 'system') + sql = "ALTER USER #{merged_name} IDENTIFIED WITH" + sql += if plugin == 'caching_sha2_password' + " caching_sha2_password AS X'#{string[2..-1]}'" + else + " mysql_native_password AS '#{string}'" + end + self.class.mysql_caller(sql, 'system') else # default ... if mysqld_version does not work self.class.mysql_caller("SET PASSWORD FOR #{merged_name} = '#{string}'", 'system') @@ -225,7 +241,11 @@ def plugin=(string) end elsif newer_than('mysql' => '5.7.6', 'percona' => '5.7.6', 'mariadb' => '10.2.0') sql = "ALTER USER #{merged_name} IDENTIFIED WITH '#{string}'" - sql += " AS '#{@resource[:password_hash]}'" if string == 'mysql_native_password' + if string == 'mysql_native_password' + sql += " AS '#{@resource[:password_hash]}'" + elsif string == 'caching_sha2_password' + sql += " AS X'#{@resource[:password_hash][2..-1]}'" + end else # See https://bugs.mysql.com/bug.php?id=67449 sql = "UPDATE mysql.user SET plugin = '#{string}'" diff --git a/manifests/db.pp b/manifests/db.pp index 84b1f743a..9247fb6c7 100644 --- a/manifests/db.pp +++ b/manifests/db.pp @@ -5,6 +5,7 @@ # mysql::db { 'mydb': # user => 'myuser', # password => 'mypass', +# plugin => 'caching_sha2_password', # host => 'localhost', # grant => ['SELECT', 'UPDATE'], # } @@ -19,6 +20,8 @@ # The user for the database you're creating. # @param password # The password for $user for the database you're creating. +# @param plugin +# The authentication plugin for $user for the database you're creating. Defaults to 'mysql_native_password'. # @param tls_options # The tls_options for $user for the database you're creating. # @param dbname @@ -49,6 +52,7 @@ define mysql::db ( String[1] $user, Variant[String, Sensitive[String]] $password, + Optional[String[1]] $plugin = undef, Optional[Array[String[1]]] $tls_options = undef, String $dbname = $name, String[1] $charset = 'utf8mb3', @@ -103,6 +107,7 @@ $user_resource = { ensure => $ensure, password_hash => Deferred('mysql::password', [$password]), + plugin => $plugin, tls_options => $tls_options, } ensure_resource('mysql_user', "${user}@${host}", $user_resource)