Connect Rails 3 to Salesforce/Any other App via OAuth - ruby

Has anybody connected to Salesforce through Rails 3 App via oauth? Could you please post code for doing same. I am trying to same but I get some error below is my code
def oauth_client
consumer_key = '....'
consumer_secret = '....'
oauth_options = {
:site => 'https://login.salesforce.com',
:scheme => :body,
:request_token_path => '/_nc_external/system/security/oauth/RequestTokenHandler',
:authorize_path => '/setup/secur/RemoteAccessAuthorizationPage.apexp',
:access_token_path => '/_nc_external/system/security/oauth/AccessTokenHandler',
}
OAuth::Consumer.new consumer_key, consumer_secret, oauth_options
end
def oauth_redirect_uri
uri = URI.parse(request.url)
uri.path = '/sfdc/oauth_callback'
uri.query = nil
# uri = "http://localhost:3000/sfdc/oauth_callback"
uri.to_s
end
def oauth_connect
consumer_key = '...' # from SalesForce
consumer = oauth_client
request_t = consumer.get_request_token
redirect_to request_t.authorize_url(
:redirect_uri => oauth_redirect_uri,
:oauth_consumer_key => consumer_key
)
end
def oauth_callback
access = request_t.get_access_token :oauth_verifier => params[:oauth_verifier]
p access
render :text => access.token
end
Error undefined method get_access_token for #<ActionDispatch::Request:0x12b79f370>. the request variable is nil here. How do I get it back?

The rforce gem has quite a bit of an example that I pasted below. However you might just want to use rforce instead of rolling your own.
def init_server(url)
#url = URI.parse(url)
if (#oauth)
consumer = OAuth::Consumer.new \
#oauth[:consumer_key],
#oauth[:consumer_secret],
{
:site => url,
:proxy => #proxy
}
consumer.http.set_debug_output $stderr if show_debug
#server = OAuth::AccessToken.new \
consumer,
#oauth[:access_token],
#oauth[:access_secret]
class << #server
alias_method :post2, :post
end
else
#server = Net::HTTP.Proxy(#proxy).new(#url.host, #url.port)
#server.use_ssl = #url.scheme == 'https'
#server.verify_mode = OpenSSL::SSL::VERIFY_NONE
# run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
#server.set_debug_output $stderr if show_debug
end
end

Related

How do I access the Magento REST API with Ruby?

I want to start working with Magento's REST API, but I can't seem to get it working.
To start with I need to get access tokens, here's what I'm trying:
require 'oauth'
#consumer = OAuth::Consumer.new("4200100753b2c8b03bde1f5b062c5a80", "c06abdcb734c85dfd7bb115c6a67ae4d", {:site=>"http://178.62.173.99/"})
#request_token = #consumer.get_request_token
# => oauth-0.4.7/lib/oauth/consumer.rb:216:in `token_request': 404 Not Found (OAuth::Unauthorized)
But I keep getting a 404 error.
What should I try next?
Here's a Ruby module I've written to create an access token for the Magento REST API:
module Token
def create_consumer
OAuth::Consumer.new(
CONSUMER_KEY,
CONSUMER_SECRET,
:request_token_path => '/oauth/initiate',
:authorize_path=>'/admin/oauth_authorize',
:access_token_path=>'/oauth/token',
:site => URL
)
end
def request_token(args = {})
args[:consumer].get_request_token(:oauth_callback => URL)
end
def get_authorize_url(args = {})
args[:request_token].authorize_url(:oauth_callback => URL)
end
def authorize_application(args = {})
m = Mechanize.new
m.get(args[:authorize_url]) do |login_page|
auth_page = login_page.form_with(:action => "#{URL}/index.php/admin/oauth_authorize/index/") do |form|
form.elements[1].value = ADMIN_USERNAME
form.elements[2].value = ADMIN_PASSWORD
end.submit
authorize_form = auth_page.forms[0]
#callback_page = authorize_form.submit
end
#callback_page.uri.to_s
end
def extract_oauth_verifier(args = {})
callback_page = "#{args[:callback_page]}".gsub!("#{URL}/?", '')
callback_page_query_string = CGI::parse(callback_page)
callback_page_query_string['oauth_verifier'][0]
end
def get_access_token(args = {})
args[:request_token].get_access_token(:oauth_verifier => args[:oauth_verifier])
end
def save_tokens_to_json(args = {})
auth = {}
auth[:time] = Time.now
auth[:token] = args[:access_token].token
auth[:secret] = args[:access_token].secret
File.open("#{args[:path]}#{args[:filename]}.json", 'w') {|f| f.write(auth.to_json)}
auth
end
def get_new_access_tokens
new_consumer = self.create_consumer
new_request_token = self.request_token(consumer: new_consumer)
new_authorize_url = self.get_authorize_url(request_token: new_request_token)
authorize_new_application = self.authorize_application(authorize_url: new_authorize_url)
extract_new_oauth_verifier = self.extract_oauth_verifier(callback_page: authorize_new_application)
new_access_token = self.get_access_token(request_token: new_request_token, oauth_verifier: extract_new_oauth_verifier)
save_tokens_to_json(filename: 'magento_oauth_access_tokens', path: '/', access_token: new_access_token)
return 'Successfully obtained new access tokens.'
end
end
Run #get_new_access_tokens to get an access token.
Don't forget to define the following variable:
CONSUMER_KEY
CONSUMER_SECRET
URL
ADMIN_USERNAME
ADMIN_PASSWORD
Check out mage on rails. It should work right out of the box. Check out this page for annotated ruby code showcasing the oauth flow

Validate In-App-Purchase Android/Google on Server side

I would like to use the purchase token from the in app purchases in an android app to validate it to the google server on my own server.
With the following code I can validate a token, but I have to authenticate myself with my OAuth credentials every time:
class GooglePlayVerification
require 'google/api_client'
# Refer:
# https://code.google.com/p/google-api-ruby-client/issues/detail?id=72
# and
# http://jonathanotto.com/blog/google_oauth2_api_quick_tutorial.html
# and
# http://milancermak.wordpress.com/2012/08/24/server-side-verification-of-google-play-subsc/
GOOGLE_KEY = 'xxx.apps.googleusercontent.com'
GOOGLE_SECRET = 'xxxx'
APP_NAME = 'xx.xx.xx'
SCOPE = "https://www.googleapis.com/auth/androidpublisher"
def self.token
##token ||= begin
require 'oauth2'
raise "Missing client_id variable" if GOOGLE_KEY.to_s.empty?
raise "Missing client_secret variable" if GOOGLE_SECRET.to_s.empty?
raise "Missing scope variable" if SCOPE.to_s.empty?
redirect_uri = 'https://localhost/oauth2callback'
auth_client_obj = OAuth2::Client.new(GOOGLE_KEY, GOOGLE_SECRET, {:site => 'https://accounts.google.com', :authorize_url => "/o/oauth2/auth", :token_url => "/o/oauth2/token"})
puts "1) Paste this URL into your browser where you are logged in to the relevant Google account\n\n"
puts auth_client_obj.auth_code.authorize_url(:scope => SCOPE, :access_type => "offline", :redirect_uri => redirect_uri, :approval_prompt => 'force')
puts "\n\n\n2) Accept the authorization request from Google in your browser:"
puts "\n\n\n3) Google will redirect you to localhost, but just copy the code parameter out of the URL they redirect you to, paste it here and hit enter:\n"
code = gets.chomp.strip
access_token_obj = auth_client_obj.auth_code.get_token(code, {:redirect_uri => redirect_uri, :token_method => :post})
puts "Result: #{access_token_obj.inspect}\n\n"
puts "Token is: #{access_token_obj.token}"
puts "Refresh token is: #{access_token_obj.refresh_token}"
{
:access_token => access_token_obj.token,
:refresh_token => access_token_obj.refresh_token,
:expires_in => access_token_obj.expires_in,
:expires_at => access_token_obj.expires_at
}
end
end
def self.refresh_token
refresh_client_obj = OAuth2::Client.new(GOOGLE_KEY, GOOGLE_SECRET, {:site => 'https://accounts.google.com', :authorize_url => '/o/oauth2/auth', :token_url => '/o/oauth2/token'})
refresh_access_token_obj = OAuth2::AccessToken.new(refresh_client_obj, token[:access_token], {refresh_token: token[:refresh_token]})
refresh_access_token_obj.refresh!
puts "refresh token: #{refresh_access_token_obj.inspect}"
##token = {
:access_token => refresh_access_token_obj.token,
:refresh_token => refresh_access_token_obj.refresh_token,
:expires_in => refresh_access_token_obj.expires_in,
:expires_at => refresh_access_token_obj.expires_at
}
end
# ie. https://developers.google.com/android-publisher/v1/
# eg.
# #subscription_id com.stocklight.stocklight.standardsubscription
# #purchase_token xxx
def self.verify_subscription(subscription_id, purchase_token)
response = RestClient.get "https://www.googleapis.com/androidpublisher/v1.1/applications/#{APP_NAME}/inapp/#{subscription_id}/purchases/#{purchase_token}?access_token=#{token[:access_token]}"
puts "Respnse \n #{response.inspect}"
puts response.code == 200
puts JSON.parse(response)
return response.code == 200 && JSON.parse(response)['kind'] =='androidpublisher#inappPurchase'
rescue
return false
end
end
Has anyone an idea how to authenticate a server without such things like OAuth on the server? Is there another authentification possibility?
Thanks!
Here is my ruby code:
def self.verify_subscription(subscription_id, transaction_id)
json = JSON.parse(transaction_id)
order = ["orderId", "packageName", "productId", "purchaseTime", "purchaseState", "purchaseToken"]
signature = json["signature"]
data = {}
order.each do |o|
data[o] = json[o]
end
key = OpenSSL::PKey::RSA.new(Base64.decode64(GOOGLE_PUBLIC_KEY))
verified = key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(signature), data.to_json)
verified
end

Force rebuild the SOAP-Header after authenticating

My SOAP-Server expects every request to have a valid token in the soap-header to authenticate the soap-client. This token is only valid for a certain period of time, so I have to expect it to be invalid in every call.
I am trying to find a way to force savon to rebuild the SOAP-Header (i.e. use the new auth-token) after I (re)authenticate with the SOAP-Server. I am not sure, if that is either a savon problem or a ruby one. Here is what I have so far.
class Soapservice
extend Savon::Model
# load stored auth-token
##header_data = YAML.load_file "settings.yaml"
client wsdl: 'locally-cached-wsdl.xml',
soap_header: {'verifyingToken' => ##header_data}
operations :get_authentification_token, :get_server_time
# request a new auth-token and store it
def get_authentification_token
response = super(:message => {
'oLogin' => {
'Username' => 'username',
'Userpass' => 'password'
}
})
settings = {
'UserID' => response[:user_id].to_i,
'Token' => response[:token],
}
File.open("settings.yaml", "w") do |file|
file.write settings.to_yaml
end
##header_data = settings
end
def get_server_time
return super()
rescue Savon::SOAPFault => error
fault_code = error.to_hash[:fault][:faultstring]
if fault_code == 'Unauthorized Request - Invalide Token'
get_authentification_token
retry
end
end
end
When I call
webservice = Soapservice.new
webservice.get_server_time
with an invalid Token, it reauthenticates and saves the new Token successfully, but the retry doesn't load the new header (the result is an infinite loop). Any ideas?
I added rubiii's answer from the GitHub-Issue here for future reference:
class Soapservice
# load stored auth-token
##header_data = YAML.load_file "settings.yaml"
def initialize
#client = Savon.client(wsdl: 'locally-cached-wsdl.xml')
end
def call(operation_name, locals = {})
#client.globals[:soap_header] = {'verifyingToken' => ##header_data}
#client.call(operation_name, locals)
end
# request a new auth-token and store it
def get_authentification_token
message = {
'Username' => 'username',
'Userpass' => 'password'
}
response = call(:get_authentification_token, :message => message)
settings = {
'UserID' => response[:user_id].to_i,
'Token' => response[:token],
}
File.open("settings.yaml", "w") do |file|
file.write settings.to_yaml
end
##header_data = settings
end
def get_server_time
call(:get_server_time)
rescue Savon::SOAPFault => error
fault_code = error.to_hash[:fault][:faultstring]
if fault_code == 'Unauthorized Request - Invalide Token'
get_authentification_token
retry
end
end
end
rubiii added:
notice that i removed Savon::Model, as you actually don't need it and i don't know if it supports this workaround.
if you look at the #call method, it accesses and changes the globals before every request.

Standardizing api responses in a modular Sinatra application

I'm developing an api as a modular Sinatra web application and would like to standardize the responses that are returned without having to do so explicitly. I thought this could be achieved by using middleware but it fails in most scenarios. The below sample application is what I have so far.
config.ru
require 'sinatra/base'
require 'active_support'
require 'rack'
class Person
attr_reader :name, :surname
def initialize(name, surname)
#name, #surname = name, surname
end
end
class MyApp < Sinatra::Base
enable :dump_errors, :raise_errors
disable :show_exceptions
get('/string') do
"Hello World"
end
get('/hash') do
{"person" => { "name" => "john", "surname" => "smith" }}
end
get('/array') do
[1,2,3,4,5,6,7, "232323", '3245235']
end
get('/object') do
Person.new('simon', 'hernandez')
end
get('/error') do
raise 'Failure of some sort'
end
end
class ResponseMiddleware
def initialize(app)
#app = app
end
def call(env)
begin
status, headers, body = #app.call(env)
response = {'status' => 'success', 'data' => body}
format(status, headers, response)
rescue ::Exception => e
response = {'status' => 'error', 'message' => e.message}
format(500, {'Content-Type' => 'application/json'}, response)
end
end
def format(status, headers, response)
result = ActiveSupport::JSON.encode(response)
headers["Content-Length"] = result.length.to_s
[status, headers, result]
end
end
use ResponseMiddleware
run MyApp
Examples (in JSON):
/string
Expected: {"status":"success","data":"Hello World"}
Actual: {"status":"success","data":["Hello World"]}
/hash (works)
Expected: {"status":"success","data":{"person":{"name":"john","surname":"smith"}}}
Actual: {"status":"success","data":{"person":{"name":"john","surname":"smith"}}}
/array
Expected: {"status":"success","data": [1,2,3,4,5,6,7,"232323","3245235"]}
Actual: {"status":"error","message":"wrong number of arguments (7 for 1)"}
/object
Expected: {"status":"success","data":{"name":"simon","surname":"hernandez"}}
Actual: {"status":"success","data":[]}
/error (works)
Expected: {"status":"error","message":"Failure of some sort"}
Actual: {"status":"error","message":"Failure of some sort"}
If you execute the code, you will see that /hash and /error give back the required responses, but the rest do not. Ideally, I would not like to change anything in the MyApp class. It's currently being built on top of Sinatra 1.3.3, ActiveSupport 3.2.9 and Rack 1.4.1.
With some help from #sinatra on irc.freenode.org, I managed to get it down to what I want. I added the following to MyApp:
def route_eval
result = catch(:halt) { super }
throw :halt, {"result" => result}
end
I then changed the following line in ResponseMiddleware:
response = {'status' => 'success', 'data' => body}
to
response = {'status' => 'success', 'data' => body["result"]}
and all my test cases passed.

Illegal characters in email when sent via smtp with Sendgrid on Rails 3.1.3

I am importing a list of contacts from gmail and using a checkbox to select the returned emails and send an invitation out to users after they have been selected. When I look at the my logs the output has the email in the correct format and everything seems fine.
When I look at my email activity on Sendgrid I am seeing additional characters attached to the email address hence making it fail. I do not have any issues sending email with my other mailers using sendmail but this one seems to add these additional characters and I do not know where they are coming from.
Has anyone else seen this happening? Or have a suggestion on how to fix this?
Expected result
Email: test#gmail.com
Actual result
Email: "test#gmail.com"#i04-01
user_mailer
def invitation(email_addresses)
#host = ((Rails.env == "production") ? "http://www.test.com" : "http://localhost:3000")
attachments.inline['people.jpg'] = File.read("#{Rails.root}/app/assets/images/people.jpg")
#attachments.inline['people.jpg'] = File.read("#{Rails.root}/app/assets/images/Girl.jpeg")
email_addresses.each do |email|
mail(:to => email, :subject => "Hello from test!")
end
end
user_controller
def import
##user = User.find(params[:id])
##users = User.find(session[:user_id])
begin
#sites = {"gmail" => Contacts::Gmail, "yahoo" => Contacts::Yahoo, "hotmail" => Contacts::Hotmail}
#contacts = #sites[params[:from]].new(params[:login], params[:password]).contacts
#users, #no_users = [], []
#contacts.each do |contact|
#if u = User.find(:first , :conditions => #users.email = �#{contact[1]}� , :include =>[:user])
if u = User.find(:first, :conditions => "email = '#{contact[1]}'")
#users << u
else
#no_users << {:name => contact[0], :email => contact[1]}
end
end
#if #contacts.save
#end
respond_to do |format|
format.html { render :template => 'shared/_contact_list', :layout => false }
format.xml { render :xml => #contacts.to_xml }
end
end
end
def send_bulk_mail
name_email =[]
email_addresses=[]
names=[]
post=params[:post]
post.each do |k,v|
if v=="1"
name_email << k
end
end
name_email.each do |n|
email_addresses << n.split(",")[1]
end
UserMailer.invitation(email_addresses).deliver
end
Thanks

Resources