twitter gem設定で転ける→opensslかと思いきやSSL証明書のせい

注意:Twitter gemのバージョンが5未満の設定ですので、5以上だと以下の手順の一部(Twitter.configure周辺)は無効ですゴメンナサイ

とても簡単なのだけどメモ。

gemを入れる

$ gem install twitter

だけ。

twitterに登録

Twitter Application Management
からapplicationを登録。

  • Create an application
    • Application Details
      • Name: *
      • Description: *
      • Website: *

の3項目をてきとーに入力。

そうするとDetailタブの画面にConsumer keyとConsumer secretとが表示される。Access tokenとAccess token secretが発行されていないので、一番下のボタンを押して生成。

OAuth settings

Your application's OAuth settings. Keep the "Consumer secret" a secret. This key should never be human-readable in your application.

Access level Read and write
About the application permission model
Consumer key ********
Consumer secret ********
Request token URL https://api.twitter.com/oauth/request_token
Authorize URL https://api.twitter.com/oauth/authorize
Access token URL https://api.twitter.com/oauth/access_token
Callback URL None
Sign in with Twitter Yes
Your access token

Use the access token string as your "oauth_token" and the access token secret as your "oauth_token_secret" to sign requests with your own Twitter account. Do not share your oauth_token_secret with anyone.

Access token ****-*********
Access token secret ********
Access level Read and write

なおOAuthタブのほうがコピペしやすい。
この内容を

Twitter.configure do |config|
  config.consumer_key = YOUR_CONSUMER_KEY
  config.consumer_secret = YOUR_CONSUMER_SECRET
  config.oauth_token = YOUR_OAUTH_TOKEN
  config.oauth_token_secret = YOUR_OAUTH_TOKEN_SECRET
end

Twitter by sferik

に従って設定するだけ。

とても簡単…のはずが

これで一旦はアルファベットのツイートが出来た。
続いて、日本語ツイートを入力しようとしてpryの文字化け、そこでreadlineがOS付属の物であることを思い出した。
ここでMac miniサーバで行ったのと同様にrubyの再インストールを行い、readlineが更新された日本語入力できたわーい☆では再度twitter gemでツイート、としようとしたらツイートできない。
Twitterから発行されたtokenやkeyが悪いのだろうかtwitter gemを入れたときにrbenv rehashしなかったのが悪かったかそうならばrbenv-rehashいれようだけど一度はツイート出来たし…云々と作業しても全くツイートできず。
ここで視点を変えて、Twitter検索を実行させたところ、次のエラーが出た。

/Users/riocampos/.rbenv/versions/1.9.3-p392/lib/ruby/1.9.1/net/http.rb:799:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (Twitter::Error::ClientError)

ざざっと読んでSSLが悪いことはわかる。

Ruby(Net::HTTP?)が SSL証明書を見つけることができなくて、HTTPS 接続に失敗しているのが原因らしい。Net::HTTP が、SSL証明書を見つけられるようにしてあげれば良い。
エラー:OpenSSL::SSL::SSLError SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed - komiyakの通り道

そして何気なくwhich opensslしたところ

$ which openssl
/usr/bin/openssl
$ openssl version
OpenSSL 0.9.8x 10 May 2012
$ brew upgrade openssl
Error: openssl-1.0.1e already installed

…?
homebrewでopensslを入れたのに、なぜそれを使わずにOSのを使ってるの?
ということで一旦削除して再インストール。

$ brew uninstall openssl
Uninstalling /usr/local/Cellar/openssl/1.0.1e...
$ brew install openssl
==> Downloading http://openssl.org/source/openssl-1.0.1e.tar.gz
Already downloaded: /Library/Caches/Homebrew/openssl-1.0.1e.tar.gz
==> perl ./Configure --prefix=/usr/local/Cellar/openssl/1.0.1e --openssldir=/usr
==> make
==> make test
==> make install MANDIR=/usr/local/Cellar/openssl/1.0.1e/share/man MANSUFFIX=ssl
==> Caveats
To install updated CA certs from Mozilla.org:

    brew install curl-ca-bundle

This formula is keg-only: so it was not symlinked into /usr/local.

Mac OS X already provides this software and installing another version in
parallel can cause all kinds of trouble.

The OpenSSL provided by OS X is too old for some software.

Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:

    LDFLAGS:  -L/usr/local/opt/openssl/lib
    CPPFLAGS: -I/usr/local/opt/openssl/include

==> Summary
/usr/local/Cellar/openssl/1.0.1e: 429 files, 16M, built in 6.2 minutes

再確認。

$ which openssl
/usr/bin/openssl

…orz
では--forceオプション付けたlinkを。

$ brew link openssl --force
Linking /usr/local/Cellar/openssl/1.0.1e... 1139 symlinks created
$ which openssl
/usr/local/bin/openssl

よしっ。
これでターミナルを立ち上げ直すと

$ openssl version
OpenSSL 1.0.1e 11 Feb 2013

ようやくhomebrewのopensslを使ってくれました。
ので再度rubyを再インストール(makeに時間が掛かるのに)…。

$ env CONFIGURE_OPTS="--with-readline-dir=`brew --prefix readline` --with-openssl-dir=`brew --prefix openssl`" rbenv install 1.9.3-p392

これで安心。

原因は証明書

しかし残念ながら同じエラーで転けるorz。
ということで本当の原因は別のところにある。

さて、皆さん割と homebrew で openssl 入れて brew link しちゃってる人も多いと思います。そんな環境でその openssl を使って Rubyコンパイルすると、OpenSSL 利用時に証明書エラーが発生します。
curl のサイト上で配布してる cacert.pem は、Mozilla で利用している証明書です。
証明書は curl-ca-bundle という formula で提供されているので、

$ brew install curl-ca-bundle
$ brew list curl-ca-bundle
/usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt
$ cp /usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt /usr/local/etc/openssl/cert.pem

することで、証明書を設置でき、SSL でのエラーは発生しません。
homebrew で入れた openssl を使って Ruby をコンパイルすると SSL 利用時に証明書エラーが発生する場合の対応 - Qiita

追記:

追記:curl-ca-bundleは'14/4/24ごろ正式に廃止されました。
MavericksでRuby1.9.3環境設定 - 別館 子子子子子子(ねこのここねこ)

ですので、以下の作業は好ましくない&上手く行かないと思われます。

そういえば上記のopensslインストールログにも

To install updated CA certs from Mozilla.org:

    brew install curl-ca-bundle

This formula is keg-only: so it was not symlinked into /usr/local.

って出てますよね。なるほどInternetからファイルをダウンロードする場合はcurlを使うのがほとんどだから、curlで使う証明書を更新しなきゃダメなのね。
ということで、これをやってみましょう。

$ brew install curl-ca-bundle
Warning: curl-ca-bundle-1.87 already installed

あ、入ってる。でもkeg-onlyだから手動で移してやるかリンク張るかしないとダメなのね。
コピーじゃなくシンボリックリンクを張っておこう。

$ brew list curl-ca-bundle
/usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt
$ ln -s /usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt /usr/local/etc/openssl/cert.pem

確認。

$ ls -l /usr/local/etc/openssl/
total 32
lrwxr-xr-x  1 riocampos  admin     57  6 15 02:26 cert.pem -> /usr/local/Cellar/curl-ca-bundle/1.87/share/ca-bundle.crt
drwxr-xr-x  2 riocampos  admin     68  6 14 23:11 certs
drwxr-xr-x  9 riocampos  admin    306  6 15 00:45 misc
-rw-r--r--  1 riocampos  admin  10835  6 15 00:45 openssl.cnf
drwxr-xr-x  2 riocampos  admin     68  6 14 23:11 private

これで上手く行きました☆