From e86e5df7c3bfb0691fd30430730546c06aa704a4 Mon Sep 17 00:00:00 2001 From: tigerroll Date: Wed, 13 Dec 2023 13:25:16 +0900 Subject: [PATCH 1/2] Fixed to support MySQL 8 Series. --- README.md | 6 +++--- compose.yaml | 27 +++++++++++++++++++++++++++ docker-compose.yml | 12 ------------ lib/gratan/client.rb | 4 ++-- lib/gratan/driver.rb | 19 +++++++++++++------ lib/gratan/grant_parser.rb | 4 ++-- spec/spec_helper.rb | 12 ++++++------ 7 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 compose.yaml delete mode 100644 docker-compose.yml diff --git a/README.md b/README.md index 4819a55..970506c 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ user "scott", "%" do grant "USAGE" end - on "test.*", expired: '2014/10/08', identified: "PASSWORD '*ABCDEF'" do + on "test.*", expired: '2014/10/08', identified: "*ABCDEF" do grant "SELECT" grant "INSERT" end @@ -141,9 +141,9 @@ end ```sh bundle install -docker-compose up -d +docker compose up -d bundle exec rake -# MYSQL57=1 bundle exec rake +# MYSQL80=1 bundle exec rake ``` ## Similar tools diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..25e04a2 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,27 @@ +services: + mysql57: + image: "mysql:5.7.42-debian" + platform: linux/amd64 + ports: + - "3307:3306" + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + TZ: 'Asia/Tokyo' + restart: always + networks: + - mysql-network + mysql80: + image: "mysql:8.0.28-debian" + platform: linux/amd64 + ports: + - "3308:3306" + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" + TZ: 'Asia/Tokyo' + command: --default-authentication-plugin=mysql_native_password + restart: always + networks: + - mysql-network +networks: + mysql-network: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 26713e6..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -mysql56: - image: "mysql:5.6" - ports: - - "14406:3306" - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: "yes" -mysql57: - image: "mysql:5.7" - ports: - - "14407:3306" - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: "yes" diff --git a/lib/gratan/client.rb b/lib/gratan/client.rb index a85be8d..7ae7299 100644 --- a/lib/gratan/client.rb +++ b/lib/gratan/client.rb @@ -132,9 +132,9 @@ def walk_options(user, host, expected_options, actual_options) end def walk_identified(user, host, expected_identified, actual_identified) - if actual_identified == 'PASSWORD ' + if actual_identified == '' unless @options[:ignore_password_secret] - log(:warn, "cannot change the password (`PASSWORD `)", :color => :yellow) + log(:warn, "cannot change the password (``)", :color => :yellow) end elsif expected_identified != actual_identified @driver.identify(user, host, expected_identified) diff --git a/lib/gratan/driver.rb b/lib/gratan/driver.rb index 9e24154..8946326 100644 --- a/lib/gratan/driver.rb +++ b/lib/gratan/driver.rb @@ -63,9 +63,19 @@ def flush_privileges def create_user(user, host, options = {}) objects = options[:objects] + identified = options[:options][:identified] + required = options[:required] + with_option = options[:with] + auth_plugin = options[:auth_plugin] || "mysql_native_password" grant_options = options[:options] granted = false + sql = "CREATE USER #{quote_user(user, host)}" + sql << " IDENTIFIED WITH #{auth_plugin} AS #{quote_identifier(identified)}" if identified + sql << " REQUIRE #{required}" if required + sql << " WITH #{with_option}" if with_option + update(sql) + objects.each do |object_or_regexp, object_options| expand_object(object_or_regexp).each do |object| grant(user, host, object, grant_options.merge(object_options)) @@ -85,7 +95,6 @@ def drop_user(user, host) def grant(user, host, object, options) privs = options.fetch(:privs) - identified = options[:identified] required = options[:required] with_option = options[:with] @@ -95,10 +104,8 @@ def grant(user, host, object, options) quote_user(user, host), ] - sql << " IDENTIFIED BY #{quote_identifier(identified)}" if identified sql << " REQUIRE #{required}" if required sql << " WITH #{with_option}" if with_option - begin update(sql) rescue Mysql2::Error => e @@ -110,8 +117,8 @@ def grant(user, host, object, options) end end - def identify(user, host, identifier) - sql = 'GRANT USAGE ON *.* TO %s IDENTIFIED BY %s' % [ + def identify(user, host, identifier, auth_plugin = "mysql_native_password") + sql = "ALTER USER %s IDENTIFIED WITH #{auth_plugin} AS %s" % [ quote_user(user, host), quote_identifier(identifier), ] @@ -127,7 +134,7 @@ def set_password(user, host, password, options = {}) password ||= '' unless options[:hash] - password = "PASSWORD('#{escape(password)}')" + password = "SELECT CONCAT('*', UPPER(SHA1(UNHEX(SHA1('#{escape(password)}'))))) AS PASSWORD" end sql = 'SET PASSWORD FOR %s = %s' % [ diff --git a/lib/gratan/grant_parser.rb b/lib/gratan/grant_parser.rb index e6a6f6a..b29b912 100644 --- a/lib/gratan/grant_parser.rb +++ b/lib/gratan/grant_parser.rb @@ -66,10 +66,10 @@ def parse_identified end def parse_main - md = /\AGRANT\s+(.+?)\s+ON\s+(.+?)\s+TO\s+'(.*)'@'(.+)'\z/.match(@stmt) + md = /\AGRANT\s+(.+?)\s+ON\s+(.+?)\s+TO\s+'(.*)'@'(.+)'\z/.match(@stmt.gsub('`', '\'')) privs, object, user, host = md.captures @parsed[:privs] = parse_privs(privs.strip) - @parsed[:object] = object.gsub('`', '').strip + @parsed[:object] = object.gsub('\'', '').strip @parsed[:user] = user @parsed[:host] = host end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e927f8b..2176c2f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -13,11 +13,11 @@ end end -def mysql57? - ENV['MYSQL57'] == '1' +def mysql80? + ENV['MYSQL80'] == '1' end -MYSQL_PORT = mysql57? ? 14407 : 14406 +MYSQL_PORT = mysql80? ? 3308 : 3307 def mysql client = nil @@ -127,7 +127,7 @@ def show_grants end end - if mysql57? + if mysql80? grants.each do |grant| end end @@ -148,7 +148,7 @@ def client(user_options = {}) logger: Logger.new('/dev/null'), } - if mysql57? + if mysql80? options.update( override_sql_mode: true, use_show_create_user: true, @@ -189,7 +189,7 @@ def apply(cli = client) class Array def normalize - if mysql57? + if mysql80? self.map do |i| i.sub(/ IDENTIFIED BY PASSWORD '[^']+'/, '') .sub(/ REQUIRE \w+\b/, '') From a6296224c90f00953ec5f7f82c2c28fef273ae93 Mon Sep 17 00:00:00 2001 From: tigerroll Date: Fri, 19 Jan 2024 22:49:21 +0900 Subject: [PATCH 2/2] Removed quotes in SQL generation during REVOKE and added a ruby development container to compose. --- compose.yaml | 18 ++++++++++++++++++ lib/gratan/driver.rb | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compose.yaml b/compose.yaml index 25e04a2..c8ff570 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,5 +1,6 @@ services: mysql57: + container_name: mysql57 image: "mysql:5.7.42-debian" platform: linux/amd64 ports: @@ -11,6 +12,7 @@ services: networks: - mysql-network mysql80: + container_name: mysql80 image: "mysql:8.0.28-debian" platform: linux/amd64 ports: @@ -22,6 +24,22 @@ services: restart: always networks: - mysql-network + ruby: + container_name: ruby + image: "ruby:2.5.7" + platform: linux/amd64 + environment: + TZ: 'Asia/Tokyo' + privileged: true + tty: true + restart: always + volumes: + - type: bind + source: . + target: /home/gratan + working_dir: /home/gratan + networks: + - mysql-network networks: mysql-network: driver: bridge diff --git a/lib/gratan/driver.rb b/lib/gratan/driver.rb index 8946326..ec9ad7c 100644 --- a/lib/gratan/driver.rb +++ b/lib/gratan/driver.rb @@ -173,7 +173,7 @@ def revoke(user, host, object, options = {}) def revoke0(user, host, object, privs) sql = 'REVOKE %s ON %s FROM %s' % [ - privs.join(', '), + privs.join(', ').gsub('\'', '').strip, quote_object(object), quote_user(user, host), ]