admin on April 4th, 2012

OAuth is an important standard for cross domain authentication, allowing web apps and users to share subscriptions. Per wikipedia (http://en.wikipedia.org/wiki/Oauth), sites are supporting either 1.0 or 2.0 Oauth standards.

Service Provider OAuth Protocol
VK 2.0
Facebook 2.0
Foursquare 2.0
github 2.0
Google 2.0 + 1.0 + AuthSub
Microsoft (Hotmail, Messenger, Xbox) 2.0
LinkedIn 2.0
MySpace 1.0a
Netflix 1.0a
StatusNet 1.0a
Twitter 1.0a
Vimeo 1.0a
Yahoo! 1.0a

Google actually support 3 different authentication mechanisms.

  1. AuthSub – The legacy channel subscription mechanism of the YouTube,
  2. OAuth 1.0 – But, it only works for Google Contacts, I was NOT able to authenticate against YouTube with scope (http://gdata.youtube.com), even though it was documented in http://hoisie.com/2011/09/12/using-google-oauth-with-omniauth/  using omniauth + omniauth-google gems
  3. OAuth 2.0 – I was able to successfully authenticate against it using omniauth-oauth2 + omniauth-google-oauth2 gems

Note the following:

https://accounts.google.com/ManageDomains -> for OAuth 1.0
https://code.google.com/apis/console -> OAuth2 (This is the right one for YouTube Oauth 2)
https://www.google.com/a/cpanel/[mydomain]/SetupOAuth -> Service to Your Google App admin, i.e. Gmail, Calendar, etc.

You can then $ curl https://gdata.youtube.com/feeds/api/users/default -H ‘Authorization: OAuth ya29.reset of the Key’

I made an example Rails application, showing how to authenticate using those (oauth 1.0 and oauth 2.0) standards.

In the Rails application, following files are needed.

### Rails_root/Gemfile ###

source 'https://rubygems.org'

...
#OAuth 1.0
gem 'omniauth'
gem 'omniauth-google'

#OAuth 2.0
gem 'omniauth-oauth2'
gem 'omniauth-google-oauth2'
...

 

### routes.rb ###
<App name>::Application.routes.draw do
 resources :users

root :to => 'users#index'
 match "/auth/:provider/callback" => "sessions#create"
 match "/auth/failure" => "sessions#failure"
 match "/signout" => "sessions#destroy", :as => :signout
end
### config/initializers/omniauth.rb ###

OmniAuth.config.full_host = "http://localhost:3000"

Rails.application.config.middleware.use OmniAuth::Builder do
 # OAuth 1.0 result # Access token starts with 1/xxxx
#Get Oauth 1.0 Key (domain name format) + Consumer Secret from https://accounts.google.com/ManageDomains

 # Provider     Uid                                 Access Token                                     Secret
 # google        raygao@are4.us       1/---------oauth 1 token-------       XXXXXX
 provider :google, '<key in Dname>', '<Consumer Secret>', :scope => 'http://gdata.youtube.com'

# OAuth 2.0 result, # Access token starts with ya29.xxxx
 # get it from https://code.google.com/apis/console/
 # See https://github.com/zquestz/omniauth-google-oauth2/issues/20
 # This explain OAuth2 for Google. Note, OAuth, does not return token_secret.
 #     Provider                 Uid Access        Token                   Secret
 #    google_oauth2   102425343454127939656   ya29.<rest of the stuff>    <none>
 provider :google_oauth2, '<Client ID>.apps.googleusercontent.com', '<Client Secret>', {:access_type => 'online', :approval_prompt => '', :client_id => '<domain name>'}
end

 

### sessions_controller.rb ####</pre>
require 'pp'
class SessionsController < ApplicationController
 def create
 auth = request.env["omniauth.auth"]
 puts auth
 #user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
 user = User.create_with_omniauth(auth)
 session[:user_id] = user.id
 puts '###### Callback invoked #####'
 redirect_to root_url, :notice => "Signed in!"
 end

def destroy
 session[:user_id] = nil
 redirect_to root_url, :notice => "Signed out!"
 end

def failure
 #render :text => 'Google auth failed.'
 render :text => request.env['omniauth.auth'].to_hash.inspect rescue "No Data"
 end
end

###users/index.html.erb ###

<h1>Listing users</h1>

<table>
 <tr>
 <th>Provider</th>
 <th>Uid</th>
 <th>Access Token</th>
 <th>Secret</th>
 <th></th>
 <th></th>
 <th></th>
 </tr>

<% @users.each do |user| %>
 <tr>
 <td><%= user.provider %></td>
 <td><%= user.uid %></td>
 <td><%= user.access_token %></td>
 <td><%= user.secret %></td>
 <td><%= link_to 'Show', user %></td>
 <td><%= link_to 'Edit', edit_user_path(user) %></td>
 <td><%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %></td>
 </tr>
<% end %>
</table>

<br />

<%= link_to 'New User', new_user_path %>
<br/><hr/>
<%= link_to 'Google Auth', "/auth/google" %><br/>
<%= link_to 'Google OAuth 2', "/auth/google_oauth2" %><br/>
<hr/>
curl https://gdata.youtube.com/feeds/api/users/default -H 'Authorization: OAuth ya29.<long stuff>'
<br/>
note, Oauth2 has no return secret!!!
<br/>
Setup Oauth2 here -> https://code.google.com/apis/console

generate oauth 2.0 key for Google apps


### models/user.rb ###

class User < ActiveRecord::Base
 def self.create_with_omniauth(auth)
 u = User.new()
 u.provider = auth['provider']
 u.uid = auth['uid']
 u.access_token = auth['credentials']['token']
 u.secret = auth['credentials']['secret']
 puts "*" *80
 puts auth
 puts "*" *80
 u.save
 return u
 end
end

Google Oauth 1.0 + 2.0 results

The Zip file of the app is here ->  Utube

Enjoy!!!

Tags: , , , , ,

This problem has been bugging me for the passed two days. Finally, after a lot of trial and error, I realized it was an issue concerning selecting the correct LayoutManager.

By default, containers (i.e. JPanel, JScrollPanel) added with drag and drop inside the NetBeans uses the GroupLayout. Hence, if you try to add a new runtime generated components to those containers, they won’t show up.

To solve this problem is to reset the Layout manager. So far, GridLayout and FlowLayout managers works great.

 touchmepane.setLayout(new GridLayout());

And, this solved me problem.


jPanelServerList.setLayout(new GridLayout());

 jPanelServerList.add(rayslabel,0);
 jPanelServerList.add(servericon,0);
 jPanelServerList.setBackground(Color.BLUE);
 jPanelServerList.revalidate();
 jPanelServerList.repaint();

revalidate() call is important. Otherwise, there is a lag.

Tags: , ,

admin on January 11th, 2012

A few days ago, at a job interview, someone asked the following question.

How do you find an English word’s anagrams from a file of 10,000 arbitrary words? Anagram is a random order of certain set of characters, i.e. Tea, Ate, Eat, eta are all anagrams of each other.

I tried very hard explaining to my interviewer that the best solution for solving this problem is using common sense.

While one can always perform a character sort function on each word of those 10,000 words and then sticking them in hash table (the traditional way), i.e. Hash #1 – Tea, Ate, Hash #2 – Nose, Ones. Then, match the word with those hashes. There are better ways.  Imagine performing 10,000 or more sort activities, it is such a waste of CPU time, plus storing 10,000 words in the memory just for the matching process. What an inefficient design, especially if you need to process matching across multiple 10,000 words files+. Huge Hashes, long execution time!

Anyway, my solution is based on the business rules. It is obvious that 5 letters words will never be anagrams of a 4 letters word, i.e. SNOWS is not same as SNOW. Even though they look very much similar. Hence, the following:

  1. Character Counting – Finding the length of the input word. This is as simple as doing a <word>.length() function. With that, when you read in the 10,000 words file, any words that doesn’t have the correct length can be thrown out. It will be a waste of CPU time to process and store them.
  2. Sum of character’s decimal value – Sorting function is a slow process, involving shifting characters of a word (an array, in fact). Why even wasting time, if there is a better way? We all know each character has a certain ASCII / Unicode representation. For example, the letter “A” is 65 in Decimal representation. The letter “s” is 115 in Decimal representation. Hence, the sum of decimals of “As” is 180. Doing a sum on decimal representation of characters is probably faster than sorting / character shifting of a word.  (see http://www.asciitable.com/)
  3. Regexp of Vowels + Prime number. (improved method) It is true after performing step #2, there could be collisions, i.e. Both “As” and “Gm” will have 180 as the sum of their decimal values. Again, common sense helps us solving this problems. In English, there are 5 vowels, “A”, “E”, “I”, “O”, and “U”. “A” – 65, “E” – 69, “I” – 73”, “O” – 81, “U” – 85. The numerical distance between each is even number based. Between “A” and “I”, it is 4. Between “E” and “I” is also 4. Between “I” and “O”, it is 8. And, between “O” and “U” it is also “4”. As well as, between “A” and “O”, it is 16. All those distances are based on 4, an even number. If you have studied math before, you should know that prime number is not divisible, except it’s self and number one, i.e. 11, 3, 5, and 7 are all prime numbers. To solve the mis-summing problem posed by step 2, you simply do a regexp counting of vowels. (See http://rubular.com/) with [aeiou]. In our case, we jag out the multiplication. i.e. Sum of (Vowels in Decimal representation * A prime number (for example 11)) + Sum (Constant in Decimal). I bet you the odds of seeing a collision are less than one in a billion. So, this will be our improved algorithm.

A lot of programmers like to solve problem in programmatic ways. But, common senses (business rules) are far more efficient at solving complex problems. In our case, imagine you have to do anagram matching across one hundred 10,000 words files. What speed gains you will get by applying business rules. 1. Character counting, 2) following formula => Sum of (Vowels in Decimal representation * A prime number (for example 11)) + Sum (Constant in Decimal). Newton’s method is not precise. But, after a few iterations, the numerical solution to a problem is fairly precise. Same logic applies here. (http://en.wikipedia.org/wiki/Newton’s_method)

There are multiple ways to solving a problems. All paths lead to Rome. Except, some paths are shorter and faster.

Well, my job interview is still a mystery. So far, I am still waiting for a response from that company. It’s tougher than I thought finding a job nowadays. I guess that’s an exception to common senses. :-)

Love to hear your comments!!!

Tags: ,

Raymond Gao on November 9th, 2011

OK, today, I gave my 2nd presentation of the year at the University of Burgundy, France, on following topics.

  1. Lean Start-up Methodology
  2. General Project Management techniques, i.e. Waterfall, Agile, Lean, SCRUM
  3. State of Cloud Computing industry, latest news, i.e. mergers and acquisitions, the evolution of cloud computing platforms, coolest technologies, i.e. NoSQL, Functional Language, …
  4. Microblogging &  Liberalization of communication mediums
  5. Methodology to manage risk

Yes, it was done in French again to a stadium of ~100 students. Since yesterday, I have shared with students my experience of starting company, and providing cool technologies to IT giants, i.e. Salesforce, Amazon, Oracle.

So, here is my presentation on SlideShare.

http://www.slideshare.net/rgao2009/lean-start-cloud-computing-methodology-in-french

Raymond Gao on October 4th, 2011

The process for installing Ruby 1.9.2 on Mac Lion + IDE is as follows:


# 1. Could have used homebrew. But, MacPort still works. And, RVM does not play nice with Netbeans 6.9.1
#install rubygems for 1.9 is already included in this port, no need to do a separate install.

sudo port install ruby19

#2. Change the symbolic links

cd /opt/local/bin

sudo ln -s erb1.9 erb
sudo ln -s gem1.9 gem
sudo ln -s irb1.9 irb
sudo ln -s rake1.9 rake
sudo ln -s rdoc1.9 rdoc
sudo ln -s ri1.9 ri
sudo ln -s ruby1.9 ruby
sudo ln -s testrb1.9 testrb

#3. Add /opt/local/bin in front of the $PATH in .bash_profile file

# MacPorts Installer addition on 2011-05-08_at_20:54:13: adding an appropriate PATH variable for use with MacPorts.
export PATH=/opt/local/bin:/opt/local/sbin:$PATH

# 4. install gems

sudo gem install rails

# 5. install debuggers

sudo gem install ruby-debug19
sudo gem install ruby-debug-ide19
sudo gem install linecache19

# 6. fix the defect in the ruby-debug-0.4.12  per http://noteslog.com/post/netbeans-6-9-1-ruby-1-9-2-rails-3-0-0-debugging/

The detailed instruction for fixing the gem is here. Recap as follows

line 142 (optional error) /opt/local/lib/ruby1.9/gems/1.9.1/gems/ruby-debug-ide19-0.4.12/lib/ruby-debug-ide.rb


# error line: $stderr.printf "Fast Debugger (ruby-debug-ide 0.4.9) listens on #{host}:#{port}\n"

$stderr.printf "Fast Debugger (ruby-debug-ide19 0.4.12) listens on #{host}:#{port}\n"

line 78 (serious error) /opt/local/lib/ruby1.9/gems/1.9.1/gems/ruby-debug-ide19-0.4.12/bin/rdebug-ide


#78 Debugger::PROG_SCRIPT = ARGV.shift
#replace with following:

script = ARGV.shift
Debugger::PROG_SCRIPT = (script =~ /script([\\\/])rails/ ? Dir.pwd + $1 : '') + script

Otherwise, you will get missing file error in Netbeans or other types of IDEs, when you try to debug.

Finally, if you are using Macport version of Ruby 1.9.2, you need to added the CA certificate. Otherwise, Ruby will complain with following error

OpenSSL::SSL::SSLError SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed


#solution

sudo curl http://curl.haxx.se/ca/cacert.pem -o /opt/local/etc/openssl/cert.pem

Tags: