初めてのGoogle Apps Marketplaceアプリ開発 by Ruby on Rails

公式サイトPHPJavaのサンプルはあるけど、Rubyはないので、同等のものを作りました。

「初めてのGoogle Apps Marketplaceアプリ開発 by Ruby on Rails」です。
今回はOpenIDで認証して、2-legged OAuthでGoogle Calendarからカレンダー一覧を取ってくるアプリを作ります。
Marketplaceに登録するにはインターネット上で動いていないといけないので、RubyのPaaS「Heroku」を使います。
Herokuを使えばクラウドで無料でRailsアプリを動かすことができます。*1

完成品

いきなりですが、完成したRailsアプリは以下からダウンロードできます。
とりあえず動かしたい人やソース読めばわかるよって人はこちらをどうぞ。
marketplace-hello-rails.zip
ただ、動かすには最低限「app/controllers/consumer_controller.rb」の

  @@consumer_key = 'Consumer Key'
  @@consumer_secret = 'Consumer Secret'

を修正する必要があります。

アプリ開発手順

ここから開発手順を説明します。以下の手順で進めていきます。

  1. OpenIDで認証できるようにする
  2. 2-legged OAuthでGoogle Calendarからカレンダー一覧を取ってくる
  3. Herokuに登録する
  4. Marketplaceに登録する
  5. 自分のAppsに追加する

OpenIDで認証できるようにする

これは前回の記事「RailsでGoogle AppsのOpenID対応アプリを作る - a_kimuraの日記」とほとんど同じです。
前回からの変更点は1つです。*2

  • OpenIDのnonceとassociationをDBに保存する*3

前回の記事ではファイルに保存していましたが、Herokuはファイル書き込みができないので、DBに保存します。
なので、Marketplaceアプリとして必須な修正ではありません。

active_record_openid_storeのインストール

ruby-openidのgemのサンプルの下に
\lib\ruby\gems\1.8\gems\ruby-openid-2.1.7\examples\active_record_openid_store
というディレクトリがあります。
それを/vendor/pluginsの下にそのままコピーします。

DBマイグレーションファイル作成

\vendor\plugins\active_record_openid_store\XXX_add_open_id_store_to_db.rb
を/db/migrate/にコピー。
ファイル名は20100408133856_add_open_id_store_to_db.rbなどと適当に変える。

app/controllers/consumer_controller.rbのconsumerメソッドを以下のように修正
  def consumer
    if @consumer.nil?
      store = ActiveRecordStore.new
      @consumer = OpenID::Consumer.new(session, store)
    end
    return @consumer
  end

2-legged OAuthでGoogle Calendarからカレンダー一覧を取ってくる

これは、RailsでGoogle AppsのOAuthを試す - a_kimuraの日記と似ているけど、ちょっと違う。
前の記事は3-legged。今回は2-leggedだ。簡単に言うと3-leggedはエンドユーザの認可が必要だが、2-leggedはエンドユーザの認可が必要ない。*4
Marketplaceアプリとしては2-leggedの方がいちいち各ユーザ毎に認可画面が表示されずうれしいだろう。MarketplaceアプリではAppsのドメイン管理者の人がアプリケーションをインストールするときに認可することになる。

  def oauth
    oauth_consumer = OAuth::Consumer.new(
       @@consumer_key,
       @@consumer_secret,
       {
         :site => "https://www.google.com",
         :scheme => :header,
         :http_method => :post,
         :request_token_path => "/accounts/OAuthGetRequestToken",
         :access_token_path  => "/accounts/OAuthGetAccessToken",
         :authorize_path     => "/accounts/OAuthAuthorizeToken"
       }
    )

    access_token = OAuth::AccessToken.new oauth_consumer
    response = access_token.get("https://www.google.com/calendar/feeds/default/allcalendars/full?xoauth_requestor_id=#{session[:email]}")
    case response
    when Net::HTTPSuccess
      @calendar_info = get_calendar_info(response.body)
    when Net::HTTPRedirection
      response = access_token.get(response['Location'])
      @calendar_info = get_calendar_info(response.body)
    else
      RAILS_DEFAULT_LOGGER.error "Failed to get user info via OAuth"
      flash[:notice] = "Authentication failed"
      redirect_to :action => :index
      return
    end
  end

コードはこんな感じで、認可画面にリダイレクトして、ユーザが認可後、callback URLに飛ぶみたいなコードが全部なくなる。
そして、Calendar APIを呼ぶときにxoauth_request_idというパラメータでユーザIDを渡す。

?xoauth_requestor_id=#{session[:email]}

Herokuに登録する

ここまでできたら、Herokuに登録する。
Herokuの使い方は以下の記事を参考にしてください。

すごく要約すると、gitインストールしてから、以下のコマンドを打ちます。

gem install heroku
git init
git add .
git commit -m "new app"
heroku create
git push heroku master
heroku rake db:migrate

heroku openでURLがわかります。

Marketplaceに登録する

ここはGoogle Apps Marketplaceにアプリケーションを登録する方法 - a_kimuraの日記の通りやってください。

ただし、今回はGAEは使わないので、以下の手順は飛ばしてください。

  • Google App Engineのアカウントを作成する
  • 携帯のメールアドレスを登録する
  • 空のアプリケーションを作成
  • helloworldアプリをビルドする
  • GAEへデプロイ

そして、「Google Apps Marketplaceにアプリケーションを登録する」の手順のところで、Manifestに以下のXMLを入力してください。

<?xml version="1.0" encoding="UTF-8" ?>
<ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009">
  <Name>Rails Sample(a-kimura)</Name>
  <Description>Demonstrates a simple Google Apps Marketplace application</Description>

  <!-- Administrators and users will be sent to this URL for application support -->
  <Support>
    <Link rel="support" href="http://xxxxxxxx.heroku.com/" />
  </Support>

  <!-- Show this link in Google's universal navigation for all users -->
  <Extension id="navLink" type="link">
    <Name>Rails Sample(a-kimura)</Name>
    <Url>http://xxxxxxxx.heroku.com/consumer/start?domain=${DOMAIN_NAME}</Url>
    <Scope ref="calendarAPI"/>
  </Extension>

  <!-- Declare our OpenID realm so our app is white listed -->
  <Extension id="realm" type="openIdRealm">
    <Url>http://xxxxxxxx.heroku.com/</Url>
  </Extension>

  <!-- Need access to the Calendar API -->
  <Scope id="calendarAPI">
    <Url>https://www.google.com/calendar/feeds/</Url>
    <Reason>This app displays the user's next upcoming Google Calendar appointment.</Reason>
  </Scope>
</ApplicationManifest>

http://xxxxxxxx.heroku.comはheroku openで表示されたURLで置換してください。
前回はなかったScopeタグが2-legged OAuthを使うときに必須の設定です。
プログラムでscope(どのAPIを使うか)の設定をしなかったので、ここで設定します。

動かしてみると


Google Appsのグローバルナビゲーションから追加したアプリケーション名をクリック。


なんの認可画面も表示されず、ログインユーザ情報とカレンダー一覧が表示されました。

*1:まあ無料はDBが5MBまでですが

*2:アカウント情報をsessionに入れるところも修正していますが、本筋とは関係ありません。

*3:nonceとassociationについて詳しくは⇒[Think IT] これならわかる!OpenIDの仕組み 第3回:悪意のある攻撃から身を守るには? (1/3)

*4:詳しくは⇒OAuthの仕様について 〜署名?それっておいしいの?〜 (Yahoo! JAPAN Tech Blog)