File: //usr/local/rvm/gems/ruby-2.5.9/gems/ruby-mysql-2.11.0/lib/mysql/authenticator.rb
class Mysql
class Authenticator
@plugins = {}
# @param plugin [String]
def self.plugin_class(plugin)
return @plugins[plugin] if @plugins[plugin]
raise ClientError, "invalid plugin name: #{plugin}" unless plugin.match?(/\A\w+\z/)
begin
require_relative "authenticator/#{plugin}"
rescue LoadError
return nil
end
class_name = plugin.gsub(/(?:^|_)(.)/){$1.upcase}
raise ClientError, "#{class_name} is undefined" unless self.const_defined? class_name
klass = self.const_get(class_name)
@plugins[plugin] = klass
return klass
end
def initialize(protocol)
@protocol = protocol
end
# @param plugin [String]
def get(plugin)
self.class.plugin_class(plugin)
end
# @param plugin [String]
def get!(plugin)
get(plugin) or raise ClientError, "unknown plugin: #{plugin}"
end
def authenticate(user, passwd, db, scramble, plugin_name)
plugin = (get(plugin_name) || DummyPlugin).new(@protocol)
pkt = plugin.authenticate(passwd, scramble) do |hashed|
@protocol.write Protocol::AuthenticationPacket.serialize(@protocol.client_flags, 1024**3, @protocol.charset.number, user, hashed, db, plugin.name)
end
while true
res = Protocol::AuthenticationResultPacket.parse(pkt)
case res.result
when 0 # OK
break
when 2 # multi factor auth
raise ClientError, 'multi factor authentication is not supported'
when 254 # change auth plugin
plugin = get!(res.auth_plugin).new(@protocol)
pkt = plugin.authenticate(passwd, res.scramble) do |hashed|
if passwd.nil? || passwd.empty?
@protocol.write "\0"
else
@protocol.write hashed
end
end
else
raise ClientError, "invalid packet: #{pkt.to_s}"
end
end
end
class DummyPlugin
# @param protocol [Mysql::Protocol]
def initialize(protocol)
@protocol = protocol
end
# @return [String]
def name
''
end
# @param passwd [String]
# @param scramble [String]
# @yield [String] hashed password
# @return [Mysql::Packet]
def authenticate(passwd, scramble)
yield ''
@protocol.read
end
end
end
end