Getting information from Facebook OmniAuth Authentication Hash - ruby

I am a beginner with Ruby and Rails but I managed to use OmniAuth for authentication via Facebook. Everything works fine, I am able to create users and they are able to login with Facebook.
The problem is, I would like to take some of the user data (such as email, profile photo, etc.) and save it.
Going through the README (https://github.com/mkdynamic/omniauth-facebook), I managed to find:
Here's an example Authentication Hash available in request.env['omniauth.auth']:
{
:provider => 'facebook',
:uid => '1234567',
:info => {
:nickname => 'jbloggs',
:email => 'joe#bloggs.com',
:name => 'Joe Bloggs',
:first_name => 'Joe',
:last_name => 'Bloggs',
:image => 'http://graph.facebook.com/1234567/picture?type=square',
:urls => { :Facebook => 'http://www.facebook.com/jbloggs' },
:location => 'Palo Alto, California',
:verified => true
}
}
I tried to do more searching on the Authentication Hash and got this which lists some of the information that can be fetched: https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
The thing is, I asked for certain permissions. The question is, how do I know what sort of information Facebook is sending? Unfortunately, saying the info is in request.env['omniauth.auth'] does me not much good. How do I fetch the information from here?
I am a real beginner going through the Rails tutorial (http://ruby.railstutorial.org/) but trying to create my own app by trial and error.

request.env['omniauth.auth'] will give you a hash. Check the Ruby docs for what you can do with a hash.
http://ruby-doc.org/core-1.9.3/Hash.html
For any elements that are not always going to be there you can just check for blank? (a Rails convenience method), e.g.
omniauth = request.env['omniauth.auth']
unless omniauth['info']['email'].blank?
send_spam omniauth['info']['email'] # ;)
end
You would probably find the following screencast useful if you haven't seen it already:
http://railscasts.com/episodes/235-omniauth-part-1

Related

FIWARE keyrock oauth callback - ruby

I am trying to implement/use Fiware Keyrock for authentization. Is there any tutorial/webinar on how to do it. Anyone does this ? It requires callbackurl and url of application of oauth, how to implement this in my rails application that it would communicate with keyrock (IDM). Any help is greatly appreciated, Thank you.
I have done this using the omniauth gem and using oauth2. There are several tutorials for using omniauth. You can first try another provider, like twitter.
I have created a "strategy" like this and placed it into /lib/omni_auth/strategies/filab_strategy.rb
require 'omniauth-oauth2'
module OmniAuth
module Strategies
class FilabStrategy < OmniAuth::Strategies::OAuth2
option :name, "filab"
option :client_options, {
:site => 'https://account.lab.fiware.org',
:authorize_url => 'https://account.lab.fiware.org/oauth2/authorize',
:token_url => 'https://account.lab.fiware.org/oauth2/token'
}
uid { raw_info['id'].to_s }
info do
{
'nickname' => raw_info['nickName'],
'displayName' => raw_info['displayName'],
'email' => raw_info['email'],
'name' => raw_info['displayName'],
}
end
extra do
{:raw_info => raw_info}
end
def raw_info
access_token.options[:mode] = :query
#raw_info ||= access_token.get('user.json', params: { access_token: access_token.token }).parsed
end
end
end
end
Then I configured and it the same way other more mainstream strategies are configured.

Google Cloud Ruby API Authorization / Client / Token handling

I'm struggling a bit with the Google Cloud Ruby API in a Rails app and am looking for some guidance. Here's a few questions and any help is appreciated.
key = Google::APIClient::KeyUtils.load_from_pkcs12('file.p12', 'notasecret')
client = Google::APIClient.new({:application_name => "App Name", :application_version => "1.0"})
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'url',
:audience => 'audience',
:scope => 'scope',
:issuer => '',
:signing_key => key)
client.authorization.fetch_access_token!
Probably most important:
"client.authorization.fetch_access_token!"
Does this need to be called every time? Am I supposed to be saving off the access token and using it until it expires or does the library take care of it for me?
What is this for? It works as is, but I copied this value from the example I found online. Should I be using this differently?
'notasecret'
:application_name and :application_version -- What are these used for? The doc doesn't really say. "The name of the application using the client." I seemingly can send anything in here... http://www.rubydoc.info/github/google/google-api-ruby-client/Google/APIClient
Thanks for any help. It's a bit frustrating the lack of docs on the authentication side of things for the ruby library from Google.

Grape API and HTTP Digest Authentication

I am working on creating an API for my ruby application that authenticates users based on HTTP Digest Authentication. I decided to use the Grape API library because it makes creating an API cleaner in ruby. The Grape documentation states that you can use Digest Authentication like:
http_digest({ :realm => 'Test Api', :opaque => 'app secret' }) do |username|
# lookup the user's password here
{ 'user1' => 'password1' }[username]
end
The Grape implementation above is a wrapper for Rack::Auth::Digest::MD5
Now also for security i read that as of RFC 2617 you don't need to store the password as plain text in the database you store an MD5 digest of the username:realm:password and authticate against that so i created a DataMapper model:
class Key
include DataMapper::Resource
property :id, Serial
property :username, String
property :password, String
property :active, Boolean, :default => true
property :created_at, DateTime, :default => DateTime.now
property :updated_at, DateTime
end
Now with what I provided, I am lost as to how to connect these two and make it work.
Unfortunately, Rack::Auth::Digest::MD5 expects a plaintext password on the server side.
The Grape example code shows a hard-coded lookup of password.
You could replace { 'user1' => 'password1' }[username] with
Key.first( :username => username ).password
provided you stored plaintext passwords in the Key class. You could store these reversibly-encrypted I suppose, although that doesn't add much security unless you construct relatively complex/costly schemes for key management.
Not sure if there is a way around this that would let you store hashed passwords. MD5 isn't the most secure hashing choice (although better than nothing!). If security is an important concern for your API, you will want to look beyond digest auth - using https would help, for example.
Edit: Following a bit of to-and-fro in discussions, the following variation of Grape's example does allow you to store the MD5'd password:
auth :http_digest, { :realm => { :realm => 'Llama', :passwords_hashed => true, :opaque => "7302c32d39bbacb5ed0ace096723fd" } } do |username|
Digest::MD5.hexdigest( 'fred:Llama:654321' )
end
The example gives a hard-coded username:'fred', password:'654321' response. So I think your target code is something like:
auth :http_digest, { :realm => { :realm => 'Llama', :passwords_hashed => true, :opaque => "7302c32d39bbacb5ed0ace096723fd" } } do |username|
k = Key.first( :username => username )
k ? k.password : nil
end
And you store the result of Digest::MD5.hexdigest( "#{username}:#{realm}:#{password}" ) in each user's password property.
Note the double-level hash with :realm twice. This is a bit hacky, but at least you don't have to write your own middleware, Grape is still dealing with it. This is not a documented feature of Grape or covered with tests, so may not work in future versions.

Specify token options for OmniAuth OAuth2 based strategy

I'm creating custom strategy for Nimble.com API. As they're using OAuth, it's pretty simple.
require 'omniauth-oauth2'
module OmniAuth
module Strategies
class Nimble < OmniAuth::Strategies::OAuth2
option :name, "nimble"
option :client_options, {
:site => "https://api.nimble.com",
:authorize_url => '/oauth/authorize',
:token_url => '/oauth/token'
}
# option :access_token_options, {
# :mode => :query,
# :param_name => :access_token
# }
option :provider_ignores_state, true
uid { raw_info['email'] }
info do
{
'uid' => raw_info['email'],
'name' => raw_info['name'],
'email' => raw_info['email']
}
end
extra do
{ 'raw_info' => raw_info }
end
def raw_info
access_token.options[:mode] = :query
access_token.options[:param_name] = :access_token
#raw_info ||= access_token.get('/api/users/myself/', {:parse => :json}).parsed
end
end
end
end
For passing tokens, they need to use access_token parameter in URL. When I specify options in raw_info function directly, as in sample — it's OK.
When I'm trying to specify this options in access_token_options hash (like in commented section) — parameters aren't passing to token. I'm not very good in Ruby, so I didn't figure out from libraries sources — how correctly pass parameters to access_token in OmniAuth OAuth2 descendants.
I'd like to make it "right way", so access_token initialised with correct options, plese someone point me the right way.
Thank you!
I've explored several existing strategies (GitHub, 4SQ), and looks like it's normal practice to directly modify access token options.
So I'll stay with it :)

How to use google-api-ruby-client with the Google Calendar API?

I've been reading the docs for the Google Calendar API and the google-api-ruby-client library, but I'm having a lot of trouble understanding them.
I have a Rails application that has a front end that lets users create objects called Events, and it saves them in a database on my server. What I would like is, after these Events are saved in the database, I want to call the Google Calendar API to create an event on a Google Calendar (that the server created, and only the server has access to modify that calendar).
I'm having lots of issues figuring out how to authenticate with the API using the ruby library. It doesn't make sense for me to use OAuth2 because I don't need to authorize anything with the user because I'm not interested in their data. I looked into Service Accounts (http://code.google.com/p/google-api-ruby-client/wiki/ServiceAccounts), but it looks like Google Calendars is not supported by Service Accounts.
Anyone have any ideas? This is the code I was experimenting with (using Service Accounts):
#client = Google::APIClient.new(:key => 'my_api_key')
path_to_key_file = '/somepath/aaaaaa-privatekey.p12'
passphrase = 'my_pass_phrase'
key = Google::APIClient::PKCS12.load_key(path_to_key_file, passphrase)
asserter = Google::APIClient::JWTAsserter.new(
'blah_blah#developer.gserviceaccount.com',
'https://www.googleapis.com/auth/calendar',
key)
# To request an access token, call authorize:
#client.authorization = asserter.authorize()
calendar = #client.discovered_api('calendar', 'v3')
event = {
'summary' => 'Appointment',
'location' => 'Somewhere',
'start' => {
'dateTime' => '2012-06-03T10:00:00.000-07:00'
},
'end' => {
'dateTime' => '2012-06-03T10:25:00.000-07:00'
},
'attendees' => [
{
'email' => 'attendeeEmail'
},
#...
]
}
result = #client.execute!(:api_method => calendar.events.insert,
:parameters => {'calendarId' => 'primary'},
:body => JSON.dump(event),
:headers => {'Content-Type' => 'application/json'})
Then of course I get this error message: Google::APIClient::ClientError (The user must be signed up for Google Calendar.) because the Service Account does not support Google Calendars.
I think you'll still need a real google user to host the calendar instance. But once you've got the calendar created under your identity, you can share it with the service account. In the sharing settings for the calendar, just use the email address of the service account (my service account ends with #developer.gserviceaccount.com). With the right sharing permissions, your service account can create/alter the event info, and not mess with your specific identity. From there, you can share the calendar with more people (or public) for their consumption of the mirrored events.
The other hitch I've run into is that it seems you can only authorize() the service account once per expiration period. You'll have to save the token you get and reuse it for the next hour, and then fetch a new one.
I don't know anything about Ruby. But it seems like understanding the underlying REST queries would help debug your problem. I've documented them here: http://www.tqis.com/eloquency/googlecalendar.htm
I was having trouble with this too and finally got a handle on it. The bottom line is that Google Calendar API v3 requires OAuth and you need to setup an App/Project through the Google Developer Console and then request OAuth permission on the target Google account. Once authorization is granted, you'll want to save the refresh token and use it on subsequent calls to get new access tokens (which expire!). I wrote a detailed blog post about this here: http://www.geekytidbits.com/google-calendar-api-from-ruby/ and this is my example script that should hopefully help you understand the flow:
#gem install 'google-api-client'
require 'google/api_client'
#Setup auth client
client_secrets = Google::APIClient::ClientSecrets.load #client_secrets.json must be present in current directory!
auth_client = client_secrets.to_authorization
auth_client.update!(
:scope => 'https://www.googleapis.com/auth/calendar',
:access_type => "offline", #will make refresh_token available
:approval_prompt =>'force',
:redirect_uri => 'http://www.myauthorizedredirecturl.com'
)
refresh_token_available = File.exist?('refresh_token.txt')
if !refresh_token_available
#OAuth URL - this is the url that will prompt a Google Account owner to give access to this app.
puts "Navigate browser to: '#{auth_client.authorization_uri.to_s}' and copy/paste auth code after redirect."
#Once the authorization_uri (above) is followed and authorization is given, a redirect will be made
#to http://www.myauthorizedredirecturl.com (defined above) and include the auth code in the request url.
print "Auth code: "
auth_client.code = gets
else
#If authorization has already been given and refresh token saved previously, simply set the refresh code here.
auth_client.refresh_token = File.read('refresh_token.txt')
end
#Now, get our access token which is what we will need to work with the API.
auth_client.fetch_access_token!
if !refresh_token_available
#Save refresh_token for next time
#Note: auth_client.refresh_token is only available the first time after OAuth permission is granted.
#If you need it again, the Google Account owner would have deauthorize your app and you would have to request access again.
#Therefore, it is important that the refresh token is saved after authenticating the first time!
File.open('refresh_token.txt', 'w') { |file| file.write(auth_client.refresh_token) }
refresh_token_available = true
end
api_client = Google::APIClient.new
cal = api_client.discovered_api('calendar', 'v3')
#Get Event List
puts "Getting list of events..."
list = api_client.execute(:api_method => cal.events.list,
:authorization => auth_client,
:parameters => {
'maxResults' => 20,
'timeMin' => '2014-06-18T03:12:24-00:00',
'q' => 'Meeting',
'calendarId' => 'primary'})
puts "Fetched #{list.data.items.count} events..."
#Update Event
puts "Updating first event from list..."
update_event = list.data.items[0]
update_event.description = "Updated Description here"
result = api_client.execute(:api_method => cal.events.update,
:authorization => auth_client,
:parameters => { 'calendarId' => 'primary', 'eventId' => update_event.id},
:headers => {'Content-Type' => 'application/json'},
:body_object => update_event)
puts "Done with update."
#Add New Event
puts "Inserting new event..."
new_event = cal.events.insert.request_schema.new
new_event.start = { 'date' => '2015-01-01' } #All day event
new_event.end = { 'date' => '2015-01-01' }
new_event.description = "Description here"
new_event.summary = "Summary here"
result = api_client.execute(:api_method => cal.events.insert,
:authorization => auth_client,
:parameters => { 'calendarId' => 'primary'},
:headers => {'Content-Type' => 'application/json'},
:body_object => new_event)
puts "Done with insert."

Resources