The generated RhoConnect application code includes a file called “application_controller.rb” which contains an implementation for the “login” route. This route is called when a device first connects to the RhoConnect application and provides username/password credentials.
The following diagram shows how this authenticate method is called:
If your back-end service requires authentication, simply add code to the login route and return true if authentication was successful or false to deny access to the application from this device. For example:
post "/login", :rc_handler => :authenticate do username = params[:login] password = params[:password] success = false # ... connect to backend using API and authenticate ... result = do_custom_authentication(username,password) if result.code == 200 # save the data for later use in the source adapter Store.put_value("username:#{username}:token",result.body) success = true end return success end
If your actual user name is different than the username that is input into the client, you can change the username by returning a string instead of true if authentication was successful.
post "/login", :rc_handler => :authenticate do username = params[:login] password = params[:password] success = false # ... connect to backend using API and authenticate ... result = do_custom_authentication(username,password) if result.code == 200 new_user = custom_user_mapping(username) # save the data for later use in the source adapter Store.put_value("username:#{new_user}:token",result.body) success = new_user end return success end
The code sample above demonstrates authentication by calling a method you would implement called ‘do_custom_authentication’ that returns an HTTP response object, however the actual implementation is left as an exercise. If your application needs to connect to LDAP, you can use the following sample code to perform simple authentication:
require 'net/ldap' post "/login", :rc_handler => :authenticate do username = params[:login] password = params[:password] success = false ldap = Net::LDAP.new ldap.host = "localhost" ldap.port = 389 ldap.auth "cn=#{username},dc=example,dc=com", password # we only need to bind to verify successful login success = true if ldap.bind return success end
Where the domain component “dc=example,dc=com” is replaced by your domain. For example, the ldap.auth
code above using “rhomobile.com” would be:
ldap.auth "cn=#{username},dc=rhomobile,dc=com", password
This example uses the net-ldap gem. To install this gem, run the following:
$ [sudo] gem install net-ldap
For more details about LDAP, please visit http://www.openldap.org/.
The code sample below demonstrates using an X509 certificate for authentication. See X509 certificate generation for more information about generating a cert. You can also view a sample project of the code below.
Inside of your RhoConnect app you can replace the password parameter with a pem file parameter. This parameter is expecting a string formatted for .pem with your certificate followed by your private key.
require 'socket' require 'openssl' post "/login", :rc_handler => :authenticate do username = params[:login] pem = params[:password] #assuming pem file has certificate and then private key below in pem format pem_arr = pem.split("-----END CERTIFICATE-----") pem_arr[0] << "-----END CERTIFICATE-----" socket = TCPSocket.new('my.secureserver.com', 4567) ssl_context = OpenSSL::SSL::SSLContext.new ssl_context.cert = OpenSSL::X509::Certificate.new(pem_arr[0].strip) ssl_context.key = OpenSSL::PKey::RSA.new(pem_arr[1].strip) ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context) ssl_socket.sync_close = true ca_cert = OpenSSL::X509::Certificate.new(File.open("CA.crt")) if ssl_socket.connect puts "socket connected correctly" return true else puts "socket failed to connect" return false end end
A simple Sinatra app listening on port 4567 for connections might look something like this.
require 'rubygems' require 'socket' require 'openssl' socket = TCPServer.new('my.secureserver.com', 4567) ssl_context = OpenSSL::SSL::SSLContext.new() ssl_context.cert = OpenSSL::X509::Certificate.new(File.open("server.crt")) ssl_context.key = OpenSSL::PKey::RSA.new(File.open("server.key")) ca_cert = OpenSSL::X509::Certificate.new(File.open("CA.crt")) ssl_socket = OpenSSL::SSL::SSLServer.new(socket, ssl_context) loop do connection = ssl_socket.accept Thread.new { begin #do something rescue $stderr.puts $! end } end