Hi,
Considering the problem of backgroundrb in shared hosting environment,
I've come with another temporary patch, which allow encrypted
communication between the MiddleMan and the server.
I still haven't found a better way to secure backgroundrb in shared
hosting environment, but at least, it's better than nothing.
Regards.
----- revision info -----
svn info
Path: .
URL: http://svn.devjavu.com/backgroundrb/trunk
Repository Root: http://svn.devjavu.com/backgroundrb
Repository UUID: 69d54aea-511f-0410-a924-81c4482807e4
Revision: 331
Node Kind: directory
Schedule: normal
Last Changed Author: gethemant at gmail.com
Last Changed Rev: 330
Last Changed Date: 2008-10-14 12:51:23 +0200 (Tue, 14 Oct 2008)
----- patch -----
diff -crB backgroundrb/lib/backgroundrb/bdrb_connection.rb
backgroundrb-patched/lib/backgroundrb/bdrb_connection.rb
*** backgroundrb/lib/backgroundrb/bdrb_connection.rb 2009-05-25
17:18:35.000000000 +0200
--- backgroundrb-patched/lib/backgroundrb/bdrb_connection.rb 2009-05-28
16:38:44.000000000 +0200
***************
*** 8,13 ****
--- 8,15 ----
@server_port = port
@cluster_conn = cluster_conn
@connection_status = true
+ @password = BDRB_CONFIG[:backgroundrb][:password].nil? ? false :
BDRB_CONFIG[:backgroundrb][:password]
+ @key = Digest::MD5.hexdigest(File.read(File.join(RAILS_ROOT, "config",
"backgroundrb.yml")))
end
***************
*** 65,74 ****
end
end
def dump_object data
establish_connection
raise BackgrounDRb::BdrbConnError.new("Error while connecting to the
backgroundrb server #{server_info}") unless @connection_status
!
object_dump = Marshal.dump(data)
dump_length = object_dump.length.to_s
length_str = dump_length.rjust(9,'0')
--- 67,121 ----
end
end
+ def decrypt_data(t_data)
+ if @key && t_data
+ data = Base64.decode64(t_data)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.decrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ decrypt_data = res.update(data)
+ decrypt_data << res.final
+ decrypt_data = Base64.decode64(decrypt_data)
+ tdata = decrypt_data.split("\b")
+
+ t_data = []
+ tdata.each do |t|
+ data = {}
+ t.split("\a").each do |e|
+ key_data = e.split("\r")
+ if key_data[1]
+ data[key_data[0].to_sym] = key_data[1].to_sym
+ else
+ data[key_data[0].to_sym] = ""
+ end
+ end
+ t_data << data
+ end
+ end
+ return t_data
+ end
+ def encrypt_data(data)
+ if @key
+ tdata = ""
+ data.each do |key, d|
+ tdata << "#{key}\r#{d}\a"
+ end
+ tdata = Base64.encode64(tdata)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.encrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ encrypt_data = res.update(tdata)
+ encrypt_data << res.final
+ data = Base64.encode64(encrypt_data)
+ end
+ return data
+ end
+
def dump_object data
+ data[:password] = @password
establish_connection
raise BackgrounDRb::BdrbConnError.new("Error while connecting to the
backgroundrb server #{server_info}") unless @connection_status
! data = encrypt_data(data)
object_dump = Marshal.dump(data)
dump_length = object_dump.length.to_s
length_str = dump_length.rjust(9,'0')
***************
*** 100,106 ****
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! bdrb_response
end
def all_worker_info
--- 147,153 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! decrypt_data(bdrb_response)
end
def all_worker_info
***************
*** 110,116 ****
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! bdrb_response
end
def delete_worker p_data
--- 157,163 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! decrypt_data(bdrb_response)
end
def delete_worker p_data
***************
*** 148,153 ****
--- 195,201 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
+ bdrb_response = decrypt_data(bdrb_response)
bdrb_response ? bdrb_response[:data] : nil
end
end
***************
*** 170,175 ****
--- 218,224 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb(nil) }
close_connection
+ bdrb_response = decrypt_data(bdrb_response)
bdrb_response ? bdrb_response[:data] : nil
end
end
diff -crB backgroundrb/server/lib/master_worker.rb
backgroundrb-patched/server/lib/master_worker.rb
*** backgroundrb/server/lib/master_worker.rb 2009-05-25 17:18:35.000000000
+0200
--- backgroundrb-patched/server/lib/master_worker.rb 2009-05-28
16:38:39.000000000 +0200
***************
*** 25,38 ****
end
class MasterWorker
! attr_accessor :debug_logger
include BackgrounDRb::BdrbServerHelper
# receives requests from rails and based on request type invoke
appropriate method
def receive_data p_data
@tokenizer.extract(p_data) do |b_data|
begin
t_data = load_data b_data
if t_data
case t_data[:type]
# async method invocation
when :async_invoke: async_method_invoke(t_data)
--- 25,94 ----
end
class MasterWorker
! attr_accessor :debug_logger,:password, :key
include BackgrounDRb::BdrbServerHelper
+
+ def decrypt_data(t_data)
+ if @key && t_data
+ data = Base64.decode64(t_data)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.decrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ decrypt_data = res.update(data)
+ decrypt_data << res.final
+ decrypt_data = Base64.decode64(decrypt_data)
+ t_data = {}
+ tdata = decrypt_data.split("\a")
+ tdata.each do |e|
+ key_data = e.split("\r")
+ t_data[key_data[0].to_sym] = key_data[1].to_sym
+ end
+ end
+ return t_data
+ end
+ def encrypt_data(data)
+ if @key && data
+ if data.is_a?(Array)
+ tdata = []
+ data.each do |e|
+ sdata = ""
+ e.each do |key, d|
+ sdata << "#{key}\r#{d}\a"
+ end
+ tdata << sdata
+ end
+ tdata = tdata.join("\b")
+ else
+ tdata = ""
+ data.each do |key, d|
+ tdata << "#{key}\r#{d}\a"
+ end
+ end
+ tdata = Base64.encode64(tdata)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.encrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ encrypt_data = res.update(tdata)
+ encrypt_data << res.final
+ data = Base64.encode64(encrypt_data)
+ end
+ return data
+ end
+
# receives requests from rails and based on request type invoke
appropriate method
def receive_data p_data
@tokenizer.extract(p_data) do |b_data|
begin
t_data = load_data b_data
if t_data
+ t_data = decrypt_data(t_data)
+ # check password
+ if @password && t_data[:password].to_s != @password
+ debug_logger.info("Invalid password : #{t_data.inspect}")
+ error_password(t_data)
+ return
+ end
+
case t_data[:type]
# async method invocation
when :async_invoke: async_method_invoke(t_data)
***************
*** 55,67 ****
end
end
# Send worker info to the user
def pass_worker_info(t_data)
worker_name_key = gen_worker_key(t_data[:worker],t_data[:worker_key])
worker_instance = reactor.live_workers[worker_name_key]
info_response = { :worker => t_data[:worker],:worker_key =>
t_data[:worker_key]}
worker_instance ? (info_response[:status] = :running) :
(info_response[:status] = :stopped)
! send_object(info_response)
end
# collect all worker info in an array and send to the user
--- 111,132 ----
end
end
+ # Send password require info to the user
+ def error_password(t_data)
+ worker_name_key = gen_worker_key(t_data[:worker],t_data[:worker_key])
+ worker_instance = reactor.live_workers[worker_name_key]
+ info_response = { :error => "Password required / Wrong password" }
+ worker_instance ? (info_response[:status] = :running) :
(info_response[:status] = :stopped)
+ send_object(encrypt_data(info_response))
+ end
+
# Send worker info to the user
def pass_worker_info(t_data)
worker_name_key = gen_worker_key(t_data[:worker],t_data[:worker_key])
worker_instance = reactor.live_workers[worker_name_key]
info_response = { :worker => t_data[:worker],:worker_key =>
t_data[:worker_key]}
worker_instance ? (info_response[:status] = :running) :
(info_response[:status] = :stopped)
! send_object(encrypt_data(info_response))
end
# collect all worker info in an array and send to the user
***************
*** 71,77 ****
worker_key = (value.worker_key.to_s).gsub(/#{value.worker_name}_?/,"")
info_response << { :worker => value.worker_name,:worker_key =>
worker_key,:status => :running }
end
! send_object(info_response)
end
# Delete the worker. Sends TERM signal to the worker process and removes
--- 136,142 ----
worker_key = (value.worker_key.to_s).gsub(/#{value.worker_name}_?/,"")
info_response << { :worker => value.worker_name,:worker_key =>
worker_key,:status => :running }
end
! send_object(encrypt_data(info_response))
end
# Delete the worker. Sends TERM signal to the worker process and removes
***************
*** 155,161 ****
# Receieve responses from workers and dispatch them back to the client
def worker_receive p_data
! send_object(p_data)
end
def unbind; end
--- 220,226 ----
# Receieve responses from workers and dispatch them back to the client
def worker_receive p_data
! send_object(encrypt_data(p_data))
end
def unbind; end
***************
*** 163,168 ****
--- 228,235 ----
# called whenever a new connection is made.Initializes binary data parser
def post_init
@tokenizer = Packet::BinParser.new
+ @password = BDRB_CONFIG[:backgroundrb][:password].nil? ? false :
BDRB_CONFIG[:backgroundrb][:password]
+ @key = Digest::MD5.hexdigest(File.read(File.join(RAILS_ROOT, "config",
"backgroundrb.yml")))
end
def connection_completed; end
end
--
SECHAUD Gaël
diff -crB backgroundrb/lib/backgroundrb/bdrb_connection.rb backgroundrb-patched/lib/backgroundrb/bdrb_connection.rb
*** backgroundrb/lib/backgroundrb/bdrb_connection.rb 2009-05-25 17:18:35.000000000 +0200
--- backgroundrb-patched/lib/backgroundrb/bdrb_connection.rb 2009-05-28 16:38:44.000000000 +0200
***************
*** 8,13 ****
--- 8,15 ----
@server_port = port
@cluster_conn = cluster_conn
@connection_status = true
+ @password = BDRB_CONFIG[:backgroundrb][:password].nil? ? false : BDRB_CONFIG[:backgroundrb][:password]
+ @key = Digest::MD5.hexdigest(File.read(File.join(RAILS_ROOT, "config", "backgroundrb.yml")))
end
***************
*** 65,74 ****
end
end
def dump_object data
establish_connection
raise BackgrounDRb::BdrbConnError.new("Error while connecting to the backgroundrb server #{server_info}") unless @connection_status
!
object_dump = Marshal.dump(data)
dump_length = object_dump.length.to_s
length_str = dump_length.rjust(9,'0')
--- 67,121 ----
end
end
+ def decrypt_data(t_data)
+ if @key && t_data
+ data = Base64.decode64(t_data)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.decrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ decrypt_data = res.update(data)
+ decrypt_data << res.final
+ decrypt_data = Base64.decode64(decrypt_data)
+ tdata = decrypt_data.split("\b")
+
+ t_data = []
+ tdata.each do |t|
+ data = {}
+ t.split("\a").each do |e|
+ key_data = e.split("\r")
+ if key_data[1]
+ data[key_data[0].to_sym] = key_data[1].to_sym
+ else
+ data[key_data[0].to_sym] = ""
+ end
+ end
+ t_data << data
+ end
+ end
+ return t_data
+ end
+ def encrypt_data(data)
+ if @key
+ tdata = ""
+ data.each do |key, d|
+ tdata << "#{key}\r#{d}\a"
+ end
+ tdata = Base64.encode64(tdata)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.encrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ encrypt_data = res.update(tdata)
+ encrypt_data << res.final
+ data = Base64.encode64(encrypt_data)
+ end
+ return data
+ end
+
def dump_object data
+ data[:password] = @password
establish_connection
raise BackgrounDRb::BdrbConnError.new("Error while connecting to the backgroundrb server #{server_info}") unless @connection_status
! data = encrypt_data(data)
object_dump = Marshal.dump(data)
dump_length = object_dump.length.to_s
length_str = dump_length.rjust(9,'0')
***************
*** 100,106 ****
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! bdrb_response
end
def all_worker_info
--- 147,153 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! decrypt_data(bdrb_response)
end
def all_worker_info
***************
*** 110,116 ****
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! bdrb_response
end
def delete_worker p_data
--- 157,163 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
! decrypt_data(bdrb_response)
end
def delete_worker p_data
***************
*** 148,153 ****
--- 195,201 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb() }
close_connection
+ bdrb_response = decrypt_data(bdrb_response)
bdrb_response ? bdrb_response[:data] : nil
end
end
***************
*** 170,175 ****
--- 218,224 ----
bdrb_response = nil
@mutex.synchronize { bdrb_response = read_from_bdrb(nil) }
close_connection
+ bdrb_response = decrypt_data(bdrb_response)
bdrb_response ? bdrb_response[:data] : nil
end
end
diff -crB backgroundrb/server/lib/master_worker.rb backgroundrb-patched/server/lib/master_worker.rb
*** backgroundrb/server/lib/master_worker.rb 2009-05-25 17:18:35.000000000 +0200
--- backgroundrb-patched/server/lib/master_worker.rb 2009-05-28 16:38:39.000000000 +0200
***************
*** 25,38 ****
end
class MasterWorker
! attr_accessor :debug_logger
include BackgrounDRb::BdrbServerHelper
# receives requests from rails and based on request type invoke appropriate method
def receive_data p_data
@tokenizer.extract(p_data) do |b_data|
begin
t_data = load_data b_data
if t_data
case t_data[:type]
# async method invocation
when :async_invoke: async_method_invoke(t_data)
--- 25,94 ----
end
class MasterWorker
! attr_accessor :debug_logger,:password, :key
include BackgrounDRb::BdrbServerHelper
+
+ def decrypt_data(t_data)
+ if @key && t_data
+ data = Base64.decode64(t_data)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.decrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ decrypt_data = res.update(data)
+ decrypt_data << res.final
+ decrypt_data = Base64.decode64(decrypt_data)
+ t_data = {}
+ tdata = decrypt_data.split("\a")
+ tdata.each do |e|
+ key_data = e.split("\r")
+ t_data[key_data[0].to_sym] = key_data[1].to_sym
+ end
+ end
+ return t_data
+ end
+ def encrypt_data(data)
+ if @key && data
+ if data.is_a?(Array)
+ tdata = []
+ data.each do |e|
+ sdata = ""
+ e.each do |key, d|
+ sdata << "#{key}\r#{d}\a"
+ end
+ tdata << sdata
+ end
+ tdata = tdata.join("\b")
+ else
+ tdata = ""
+ data.each do |key, d|
+ tdata << "#{key}\r#{d}\a"
+ end
+ end
+ tdata = Base64.encode64(tdata)
+ res = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
+ res.encrypt
+ res.key = Digest::SHA2.hexdigest(@key)
+ encrypt_data = res.update(tdata)
+ encrypt_data << res.final
+ data = Base64.encode64(encrypt_data)
+ end
+ return data
+ end
+
# receives requests from rails and based on request type invoke appropriate method
def receive_data p_data
@tokenizer.extract(p_data) do |b_data|
begin
t_data = load_data b_data
if t_data
+ t_data = decrypt_data(t_data)
+ # check password
+ if @password && t_data[:password].to_s != @password
+ debug_logger.info("Invalid password : #{t_data.inspect}")
+ error_password(t_data)
+ return
+ end
+
case t_data[:type]
# async method invocation
when :async_invoke: async_method_invoke(t_data)
***************
*** 55,67 ****
end
end
# Send worker info to the user
def pass_worker_info(t_data)
worker_name_key = gen_worker_key(t_data[:worker],t_data[:worker_key])
worker_instance = reactor.live_workers[worker_name_key]
info_response = { :worker => t_data[:worker],:worker_key => t_data[:worker_key]}
worker_instance ? (info_response[:status] = :running) : (info_response[:status] = :stopped)
! send_object(info_response)
end
# collect all worker info in an array and send to the user
--- 111,132 ----
end
end
+ # Send password require info to the user
+ def error_password(t_data)
+ worker_name_key = gen_worker_key(t_data[:worker],t_data[:worker_key])
+ worker_instance = reactor.live_workers[worker_name_key]
+ info_response = { :error => "Password required / Wrong password" }
+ worker_instance ? (info_response[:status] = :running) : (info_response[:status] = :stopped)
+ send_object(encrypt_data(info_response))
+ end
+
# Send worker info to the user
def pass_worker_info(t_data)
worker_name_key = gen_worker_key(t_data[:worker],t_data[:worker_key])
worker_instance = reactor.live_workers[worker_name_key]
info_response = { :worker => t_data[:worker],:worker_key => t_data[:worker_key]}
worker_instance ? (info_response[:status] = :running) : (info_response[:status] = :stopped)
! send_object(encrypt_data(info_response))
end
# collect all worker info in an array and send to the user
***************
*** 71,77 ****
worker_key = (value.worker_key.to_s).gsub(/#{value.worker_name}_?/,"")
info_response << { :worker => value.worker_name,:worker_key => worker_key,:status => :running }
end
! send_object(info_response)
end
# Delete the worker. Sends TERM signal to the worker process and removes
--- 136,142 ----
worker_key = (value.worker_key.to_s).gsub(/#{value.worker_name}_?/,"")
info_response << { :worker => value.worker_name,:worker_key => worker_key,:status => :running }
end
! send_object(encrypt_data(info_response))
end
# Delete the worker. Sends TERM signal to the worker process and removes
***************
*** 155,161 ****
# Receieve responses from workers and dispatch them back to the client
def worker_receive p_data
! send_object(p_data)
end
def unbind; end
--- 220,226 ----
# Receieve responses from workers and dispatch them back to the client
def worker_receive p_data
! send_object(encrypt_data(p_data))
end
def unbind; end
***************
*** 163,168 ****
--- 228,235 ----
# called whenever a new connection is made.Initializes binary data parser
def post_init
@tokenizer = Packet::BinParser.new
+ @password = BDRB_CONFIG[:backgroundrb][:password].nil? ? false : BDRB_CONFIG[:backgroundrb][:password]
+ @key = Digest::MD5.hexdigest(File.read(File.join(RAILS_ROOT, "config", "backgroundrb.yml")))
end
def connection_completed; end
end
_______________________________________________
Backgroundrb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/backgroundrb-devel