Resolve #7959, Automatically login to RPC service after expiration

When the RPC client token expires, it will automatically login
again, and renew the token during the next RPC request.

Resolves #7959
bug/bundler_fix
wchen-r7 2017-02-14 16:41:08 -06:00
parent 082ebe23db
commit 81abbfba46
1 changed files with 45 additions and 15 deletions

View File

@ -28,6 +28,9 @@ class Client
# @option info [String] :token A token used by the client. # @option info [String] :token A token used by the client.
# @return [void] # @return [void]
def initialize(info={}) def initialize(info={})
@user = nil
@pass = nil
self.info = { self.info = {
:host => '127.0.0.1', :host => '127.0.0.1',
:port => 3790, :port => 3790,
@ -41,14 +44,16 @@ class Client
end end
# Logs in by calling the 'auth.login' API. The authentication token will expire 5 minutes # Logs in by calling the 'auth.login' API. The authentication token will expire after 5
# after the last request was made. # minutes, but will automatically be rewnewed when you make a new RPC request.
# #
# @param [String] user Username. # @param [String] user Username.
# @param [String] pass Password. # @param [String] pass Password.
# @raise RuntimeError Indicating a failed authentication. # @raise RuntimeError Indicating a failed authentication.
# @return [TrueClass] Indicating a successful login. # @return [TrueClass] Indicating a successful login.
def login(user,pass) def login(user,pass)
@user = user
@pass = pass
res = self.call("auth.login", user, pass) res = self.call("auth.login", user, pass)
unless (res && res['result'] == "success") unless (res && res['result'] == "success")
raise RuntimeError, "authentication failed" raise RuntimeError, "authentication failed"
@ -58,6 +63,14 @@ class Client
end end
# Attempts to login again with the last known user name and password.
#
# @return [TrueClass] Indicating a successful login.
def re_login
login(@user, @pass)
end
# Calls an API. # Calls an API.
# #
# @param [String] meth The RPC API to call. # @param [String] meth The RPC API to call.
@ -84,6 +97,36 @@ class Client
args.unshift(meth) args.unshift(meth)
begin
send_rpc_request(args)
rescue Msf::RPC::ServerException => e
if e.message =~ /Invalid Authentication Token/i && meth != 'auth.login'
re_login
args[1] = self.token
retry
else
raise e
end
ensure
@cli.close if @cli
end
end
# Closes the client.
#
# @return [void]
def close
if @cli && @cli.conn?
@cli.close
end
@cli = nil
end
private
def send_rpc_request(args)
unless @cli unless @cli
@cli = Rex::Proto::Http::Client.new(info[:host], info[:port], info[:context], info[:ssl], info[:ssl_version]) @cli = Rex::Proto::Http::Client.new(info[:host], info[:port], info[:context], info[:ssl], info[:ssl_version])
@cli.set_config( @cli.set_config(
@ -101,7 +144,6 @@ class Client
) )
res = @cli.send_recv(req) res = @cli.send_recv(req)
@cli.close
if res && [200, 401, 403, 500].include?(res.code) if res && [200, 401, 403, 500].include?(res.code)
resp = MessagePack.unpack(res.body) resp = MessagePack.unpack(res.body)
@ -118,18 +160,6 @@ class Client
end end
end end
# Closes the client.
#
# @return [void]
def close
if @cli && @cli.conn?
@cli.close
end
@cli = nil
end
end end
end end
end end