Rails 3 - Devise/ActionMailer/RUBY-SMTP causing a segmentation fault - ruby

OK - I'm in way over my head here. I'm using:
- ruby-1.9.3-p0
- rails-3.1.3
- mail-2.3.0
- devise-1.5.3
Trying to turn on Devise's :confirmable option and start up smtp services in my app. As soon as I add /config/initializers/setup_mail.rb, add Devise's necessary columns in my DB, and the :confirmable attribute to my User model, I get a segmentation fault. It occurs right after a user signs up. Devise is trying to send out the confirmation email, causing the ruby smtp library to crash with the following:
... lib/ruby/1.9.1/net/smtp.rb:583: [BUG] Segmentation fault
The last entry in log/development.log:
Rendered devise/mailer/confirmation_instructions.html.erb (1.2ms)
My /config/initializers/setup_mail.rb file:
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "mydomain.com",
:user_name => "support#mydomain.com",
:password => "???????",
:authentication => "plain",
:enable_starttls_auto => true
}
ActionMailer::Base.default_url_options[:host] = "localhost:3000"
My config/environments/development.rb file has the following:
config.action_mailer.delivery_method = :smtp
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
Here is the germane code from ruby/1.9.1/net/smtp.rb (line 583 is near the middle):
def ssl_socket(socket, context)
OpenSSL::SSL::SSLSocket.new socket, context
end
def tlsconnect(s)
verified = false
s = ssl_socket(s, #ssl_context)
logging "TLS connection started"
s.sync_close = true
s.connect # THIS IS LINE 583
if #ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
s.post_connection_check(#address)
end
verified = true
s
ensure
s.close unless verified
end
It looks like the segmentation fault occurs when smtp is trying to connect via a SSL socket connection ( s.connect ). In setup_mail.rb I've tried setting :enable_starttls_auto to both true and false. I don't get the segmentation fault when it is set to false but no email goes out, so that is useless.
I'm easily able to connect to gmail's smtp service by running this command from my Mac:
$ telnet smtp.gmail.com 587
Not sure where to go from here - any suggestions?

I had a very similar error (in net/http).
Doing this fixed it:
rvm pkg install openssl
rvm pkg install iconv
rvm pkg install readline
rvm reinstall 1.9.3 --with-iconv-dir=$rvm_path/usr --with-openssl-dir=$rvm_path/usr --with-readline-dir=$rvm_path/usr

The issue is with the way Rails interacts with OpenSSL. This post sums it up very well. http://www.22ideastreet.com/debug/smtp-rb14-bug-segmentation-fault/
The fix is to add this to your .bashrc/.zshrc/.bash_profile
export RUBYOPT="-ropenssl"

Related

Ruby Oauth2.0: client_secret_post not working with ory hydra

I am trying to get a Ruby Oauth2.0 client talking with the Ory Hydra docker-compose 5 minute demo. I am stuck on the client app's authentication code exchange for the token. LOG is below. Looks like the main problem is the following "hashedPassword is not the hash of the given password".
DEBUG LOG FROM HYDRA SERVER
time="2019-06-04T21:32:09Z" level=info msg="started handling request" method=POST remote="172.19.0.2:35482" request=/oauth2/token
hydra_1
time="2019-06-04T21:32:09Z" level=error msg="An error occurred" debug="crypto/bcrypt: hashedPassword is not the hash of the given password" description="Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)" error=invalid_client
hydra_1
time="2019-06-04T21:32:09Z" level=info msg="completed handling request" measure#hydra/public: http://127.0.0.1:4444/.latency=92931900 method=POST remote="172.19.0.2:35482" request=/oauth2/token status=401 text_status=Unauthorized took=92.9319ms
I've read up here and it would appear this 'is' possible.
Here is how I register my client 'test-app9' in hydra:
docker-compose -f quickstart.yml exec hydra hydra clients create --endpoint http://127.0.0.1:4445 --id test-app9 --secret secret--skip-tls-verify --grant-types authorization_code,refresh_token,client_credentials,implicit --response-types token,code,id_token --scope profile --callbacks http://127.0.0.1:8088/auth/callback --token-endpoint-auth-method client_secret_post -g client_credentials
I can indeed see the client appearing in the postgres DB from the docker-compose demo. The password 'secret' is hashed in the DB.
Here is my single Sinatra file acting as the Oauth2.0 client:
require 'rubygems'
require 'sinatra'
require 'oauth2'
require 'json'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
# If you add your authentication in the header then use ~Sclient_secret_basic~T
# If you add your authentication details in the post use ~Sclient_secret_post~T
def client
OAuth2::Client.new('test-app9',
'secret',
# 'c2VjcmV0',
:site => "http://127.0.0.1:4445",
:logger => Logger.new('example.log'),
:authorize_url => "http://127.0.0.1:4444/oauth2/auth",
:token_url => "http://hydra:4444/oauth2/token")
end
set :root, File.dirname(__FILE__)
set :views, Proc.new { File.join(root, "views") }
set :run, true
set :port, 80
get "/" do
erb :index
end
get '/auth' do
authorization_url = client.auth_code.authorize_url(:redirect_uri => redirect_uri, :response_type => "code", :scope => "profile", :state => "pqrst1234")
puts "Redirecting to URL: #{authorization_url.inspect}"
redirect authorization_url
end
get '/auth/callback' do
begin
access_token = client.auth_code.get_token(params[:code], :redirect_uri => redirect_uri, :client_id => "test-app9", :client_secret => 'secret', :headers => {'Authorization' => 'basic_auth_header', 'client_id' => 'test-app9', 'client_secret' => 'c2VjcmV0'} )
api_url = "/me.json"
me = JSON.parse(access_token.get(api_url).body)
erb "<p>Your data:\n#{me.inspect}</p>"
rescue OAuth2::Error => e
erb %(<p>Wassup #{$!}</p><p>Retry</p>)
end
end
get '/auth/failure' do
erb "<h1>Authentication Failed:</h1><h3>message:<h3> <pre>#{params}</pre>"
end
def redirect_uri(path = '/auth/callback', query = nil)
uri = URI.parse(request.url)
uri.path = path
uri.query = query
uri.to_s
end
__END__
So some interesting notes:
It apparently does not matter what secret I initiate the OAuth2 client with. I can use 'secret' or the base64 encoded 'c2VjcmV0' string. Either way I get up to the token exchange portion.
I was shotgunning this and ended up putting the client_id and the client_secret in what I believe is the proper way to set in the headers as well as the body.
I have tried many variations of this. Can't seem to get the correct syntax that the author of this apparently succeeded with OR I'm hitting a bug (doubtful).
Anyone able to help here?
UPDATE
Fixed this myself. Problem was syntax issue when creating my client 'app'. This is the corrected version.
docker-compose -f quickstart.yml exec hydra hydra clients create --endpoint http://127.0.0.1:4445 --id test-app10 --secret secret --skip-tls-verify --grant-types authorization_code,refresh_token,client_credentials,implicit --response-types token,code,id_token --scope profile --callbacks http://127.0.0.1:8088/auth/callback --token-endpoint-auth-method client_secret_post -g client_credentials

Make FTPS connection in Ruby with double-bag-ftps gem

I am trying to get a native FTP connection work to an odd FTP server in ruby. It requires TLS and implicit SSL. I have a FileZilla client configured and working. Here's my code:
require 'double_bag_ftps'
DoubleBagFTPS.open(ftp_host, ftp_user, passwd, nil, DoubleBagFTPS::IMPLICIT, :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |ftp|
...
files = ftp.list(file_path)
STDOUT.write files
end
I get the following runtime error when I run the above:
bunches of traceback lines
<path_to_gems>/double-bag-ftps-0.1.4/lib/double_bag_ftps.rb:160:in `initialize': wrong argument type nil (expected OpenSSL/SSL/CTX) (TypeError)
I can't seem to get anything out of the server with Ruby and the traditional net/ftp gem (various errors related to TLS/SSL problems). DoubleBagFTPS seems to be the most promising gem, but I still get an error. It may be the case that I am not calling the open function correctly. The only nil is the fourth parameter, but that's clearly spelled out in the DooubleBagFTPS example.
Can someone help?
Update
Per the suggestion, here's my new code
class MyFTP < Net::FTP
FTP_PORT = 990
def connect(host, port = FTP_PORT)
synchronize do
#host = host
#bare_sock = open_socket(host, port)
begin
ssl_sock = start_tls_session(Socket.tcp(host, port))
#sock = BufferedSSLSocket.new(ssl_sock, read_timeout: #read_timeout)
voidresp
if #private_data_connection
voidcmd("PBSZ 0")
voidcmd("PROT P")
end
rescue OpenSSL::SSL::SSLError, Net::OpenTimeout
#sock.close
raise
end
end
end
end
def ftp_options
{
username: 'user',
password: 'password',
ssl: true,
passive: true
}
end
MyFTP.open(ftp_host, ftp_options) do |ftp|
ftp.login
files = ftp.chdir(file_path)
files = ftp.list
STDOUT.write files
end
I'm still getting an error as follows:
---stack-trace---
<path_to_gem>/ruby/2.5.0/net/protocol.rb:52:in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: unknown protocol (OpenSSL::SSL::SSLError)
So I got it working with regular old Net::FTP as follows:
def ftp_options
{
username: '<username>',
password: '<password>',
ssl: {
verify_mode: OpenSSL::SSL::VERIFY_NONE
}
}
end
Net::FTP.open(ftp_host, ftp_options) do |ftp|
ftp.login(ftp_options[:username], ftp_options[:password])
files = ftp.list
STDOUT.write files
puts "\n"
end
The one thing I don't understand is why I am forced to pass the username and password to the ftp.login method, since it's already defined in ftp_options, which was passed to Net::FTP.open(). As far as I can tell everything is set up correctly in ftp_options. For the particular server I'm connecting to, TLS/SSL is required, and that's working, so that parameter variable is being picked up... why not user/password?
Anyway, case closed for me at least. I can confirm that regular Net::FTP seems to work with at least one of these non-vanilla FTP servers requiring TLS and implicit SSL.

How to connect to FTP via SOCKS5 proxy with Ruby?

I'm trying to connect to FTP via SOCKS5 proxy using ruby's library Net::FTP. Documentation says to set env variable SOCKS_SERVER in order to connect through proxy (http://ruby-doc.org/stdlib-2.0.0/libdoc/net/ftp/rdoc/Net/FTP.html#method-i-connect), but it seems like it does not work.
Code I'm running is this:
irb(main):054:0> ftp = Net::FTP.new
=> #<Net::FTP:0x007efd08c73768 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Thread::Mutex:0x007efd08c73718>, #binary=true, #passive=true, #debug_mode=false, #resume=false, #sock=#<Net::FTP::NullSocket:0x007efd08c736f0>, #logged_in=false, #open_timeout=nil, #read_timeout=60>
irb(main):056:0> ENV['SOCKS_SERVER'] = 'host:port'
=> "host:port"
irb(main):055:0> ftp.connect('test.rebex.net')
=> nil
irb(main):057:0> ftp.login('demo', 'password')
=> true
irb(main):058:0> ftp.ls
=> ["10-27-15 03:46PM <DIR> pub", "04-08-14 03:09PM 403 readme.txt"]
When I look to proxy logs I can not see any requests going through.
What I'm doing wrong or does anybody have an example how to achieve that?
If your on Windows computer you'll need to use dress_socks gem and Monkeypath:
$socks_server = '127.0.0.1'
$socks_port = '9090'
require 'dress_socks'
class Net::FTP
def open_socket(host, port) # :nodoc:
# puts "opening socket #{#host}:#{port}"
return DressSocks::Socket.new(#host, port,
socks_server: $socks_server, socks_port: $socks_port)
end
end

Ruby hidden input password

I wrote a Ruby script that's trying to connect to a Postgres database hosted on Heroku.
If I use a hardcoded password, or if I load the password using gets, everything works fine.
However, if I load the password using IO.noecho, I get the following exception:
storing.rb:11:in `initialize': FATAL: password authentication failed for user "***" (PG::ConnectionBad)
FATAL: no pg_hba.conf entry for host "****", user "***", database "***", SSL off
from storing.rb:11:in `new'
from storing.rb:11:in `create_conn'
from fetch_currencies.rb:11:in `<main>'
Here's my code:
def create_conn(password)
conn = PGconn.connect(
:host => '***',
:port => 5432,
:dbname => '***',
:user => '***',
:password => password)
return conn
end
puts 'Postgres DB password:'
pass = STDIN.noecho(&:gets)
conn = create_conn(pass)
I tried printing the password after loading it, as well as checking whether it's a String, and everything seems to be fine. What could be the problem?
The problem, of course, was that I didn't chomp the input, so I guess the terminating new line character was also passed as part of the password.
The right way to go is then
pass = STDIN.noecho(&:gets).chomp

Ruby SOAP SSL Woes

I have a SOAP client in Ruby that I'm trying to get working with a Ruby SOAP server, to no avail. The client works fine over SSL with a Python SOAP server, but not with the Ruby version. Here's what the server looks like:
require 'soap/rpc/standaloneServer'
require 'soap/rpc/driver'
require 'rubygems'
require 'httpclient'
def cert(filename)
OpenSSL::X509::Certificate.new(File.open("path to cert.cert") { |f|
f.read
})
end
def key(filename)
OpenSSL::PKey::RSA.new(File.open("path to rsaprivate.key") { |f|
f.read
})
end
class Server < SOAP::RPC::HTTPServer
~code snipped for readability~
end
server = Server.new(:BindAddress => HelperFunctions.local_ip, :Port => 1234, :SSLCertificate => cert("path to cert"), :SSLPrivateKey => key("path to rsa private key"))
new_thread = Thread.new { server.start }
I've trimmed some of the code out for readability's sake (e.g., I have some methods in there I expose) and it works fine with SSL off. But when the client tries to connect, it sees this:
warning: peer certificate won't be verified in this SSL session
/usr/lib/ruby/1.8/net/http.rb:567: warning: using default DH parameters.
/usr/lib/ruby/1.8/net/http.rb:586:in `connect': unknown protocol (OpenSSL::SSL::SSLError)
I tried taking some advice from this post and now I see this message:
/usr/lib/ruby/1.8/soap/httpconfigloader.rb:64:in `set_ssl_config': SSL not supported (NotImplementedError)
Any ideas on how to fix this would be greatly appreciated.
Arg. I was trying to follow along this link and it turns out I was missing a simple include statement:
require 'webrick/https'
That, combined with the help from the link in the original question solves the problem. Hopefully this saves someone else down the line an hour of grief :)
"SSL not supported" can be caused by not having httpclient installed.
Me too.. and don't forget to put the :SSLEnable => true spend couple of hours figuring that out...
server = Server.new(:BindAddress => HelperFunctions.local_ip, :Port => 1234, :SSLEnable => true, :SSLCertificate => cert("path to cert"), :SSLPrivateKey => key("path to rsa private key"))

Resources