Apache Drillはuserに厳しい
mongodbに対して、user
というキーをそのまま使うと、anonymous
になってしまう。
0: jdbc:drill:zk=local> select * from mongo.test.actions t; +--------------------------------------+---------+-------------+------------------+ | _id | action | created_at | user | +--------------------------------------+---------+-------------+------------------+ | {"$oid":"5686bacac3220d960f34589c"} | add | 1451664185 | Walter Lynch | | {"$oid":"5686bad1c3220d960f34589d"} | add | 1451668314 | Irene Armstrong | | {"$oid":"5686badac3220d960f34589e"} | add | 1451671227 | Paul Bailey | | {"$oid":"5686bae1c3220d960f34589f"} | remove | 1451671349 | Walter Lynch | +--------------------------------------+---------+-------------+------------------+ 4 rows selected (0.315 seconds) 0: jdbc:drill:zk=local> select user from mongo.test.actions; +------------+ | user | +------------+ | anonymous | | anonymous | | anonymous | | anonymous | +------------+ 4 rows selected (0.171 seconds)
これはバッククォートだけでもダメで、collectionとセットで指定しないと正しく取得できない。
0: jdbc:drill:zk=local> select `user`, t.`user` from mongo.test.actions t; +------------+------------------+ | user | user0 | +------------+------------------+ | anonymous | Walter Lynch | | anonymous | Irene Armstrong | | anonymous | Paul Bailey | | anonymous | Walter Lynch | +------------+------------------+ 4 rows selected (0.133 seconds)
このanonymous
は接続ユーザ名というわけでもないようだし謎なのだけれど、サブクエリ内で集計して結果出力していたら、何故か結果が常に1行になってしまい、無駄に時間を費やしてしまった。
Apache Drill 1.2.0までは、(dfs経由での)JSONやMySQLに対してuser
というキーを使うとエラーになる問題もあったけれど、1.3.0以降で解消されていた。
0: jdbc:drill:zk=local> select user from dfs.`/tmp/actions.json`; Error: DATA_READ ERROR: Error parsing JSON - Cannot read from the middle of a record. Current token was START_ARRAY 0: jdbc:drill:zk=local> select * from mysql.mysql.`user`; Error: VALIDATION ERROR: java.lang.NullPointerException
そもそもキー名として微妙な感じもするけれど、外部データだと如何ともし難い場合があったりではあるので悩ましい。
OpenConnectによるVPN接続
概要
- Cisco AnyConnectではなく、互換クライアントのOpenConnectを利用してVPN接続を行う方法についてのメモ
- Cisco AnyConnectはVirtualboxの仮想NICと相性が悪く、VPN接続中はルーティングを全てトンネル側に向けてしまうため、仮想環境のネットワークに接続できない問題がある
- Virtualboxのネットワークに接続できないと、Vagrant上の開発環境や、Genymotion(Androidエミュレータ)が利用できなくなるので困る
- 問題の報告は以前から上がっているようだけれど、改善の気配はないみたい
- 動作確認環境は Mac OS X 10.10.5 (Yosemite)
事前準備
必要なアプリケーションのインストール
仮想ネットワークデバイス TUN/TAP
- TunTap - Home
- Yosemite以降、未署名のKernel Extensionがインストールできなくなったため sudo nvram boot-args="kext-dev-mode=1" などの回避手段が取られていたが、2014/11/18から署名済パッケージが配布されているため、現在はインストール上の問題は発生しない
$ brew cask install tuntap
Cisco互換のVPNクライアント(?) vnpc
$ brew install vpnc
OpenConnect
$ brew install openconnect
各種証明書のエクスポート
- クライアント証明をKeyChainからエクスポートする
- サーバ証明書をKeyChainからエクスポートする
- KeyChain Access.app の login にある認証局ドメイン(ca.example.comなど)の証明書を選択し、右クリックメニューなどからExportする
- 出力先は ~/.cisco/certificate/server/ca.example.com.cer に設置した
接続方法
以下の様なコマンドで接続できる。
$ sudo openconnect \ --user=username \ --authgroup=vpn \ --script=/usr/local/etc/vpnc-script \ --cafile=~/.cisco/certificate/server/ca.example.com.cer \ --certificate=~/.cisco/certificate/client/cert.p12 \ vpn.example.com
--user
は、各自接続ユーザ名に置き換える--script
は、vpncでインストールされたパスを指定する--cafile
と--certificate
は、前項でエクスポートした各証明書パスを指定するvpn.example.com
は、接続先のVPNサーバ名に置き換える--authgroup
は環境によって不要かもしれない(指定値は接続先VPN管理者に確認する)- 設定項目はファイルに切り出して接続時に読み込ませることもできる
接続終了
- 接続終了は Ctrl + C などで切断する
- 起動時に -b オプションを付加するとバックグランドで実行されるので、その場合は kill などで殺す
問題点など
signer not found のエラーが出る
- CA証明書指定が間違っているかもしれない
- とりあえず yes とか答えてスルーすることもできるが、当然微妙
- 雑に済ますなら --no-cert-check オプションでスキップすることもできる
SSL negotiation with vpn.example.com Server certificate verify failed: signer not found Certificate from VPN server "vpn.example.com" failed verification. Reason: signer not found Enter 'yes' to accept, 'no' to abort; anything else to view: yes
パスワード入力を最大3回求められる
- 「sudo」「クライアント証明書」「VPNサーバへのログイン」のそれぞれで、パスワード入力が求められる
- セキュリティ上のリスクを承知の上で、以下の様なパスワード回避手段を採用することができる
openconnect実行にsudoパスワードを省略する
$ sudo visudo -f /etc/sudoers --- # 下記の1行を追加する %admin ALL=(ALL) NOPASSWD: /usr/local/bin/openconnect
クライアント証明書からパスワードを除去する
$ cd ~/.cisco/certificate/client/ $ openssl pkcs12 -in cert.p12 -nodes -out temp.pem Enter Import Password: (エクスポート時のパスワードを入力) MAC verified OK $ openssl pkcs12 -export -in temp.pem -out cert_unprotected.p12 Enter Export Password: (何も入力せずにEnter) Verifying - Enter Export Password: (何も入力せずにEnter) $ rm temp.pem
VPNサーバへのログインパスワードを標準入力で渡す
- 標準入力からパスワードを受け取ることができるので、起動時のコマンドに含めてしまう
echo -n "password" | sudo openconnect --passwd-on-stdin vpn.example.com
切断後にネット接続できなくなることがある
- 何故か自然復旧することもあるけれど、たいてい接続できない状態のままになる
- pingを打っても下記のようなエラーが表示される感じ
$ ping 192.168.0.1 PING 192.168.0.1 (192.168.0.1): 56 data bytes ping: sendto: No route to host
- 原因はDefault Gatewayに
RTF_IFSCOPE
が立っているので、通常の接続時にgatewayとして認識してくれないみたい- ルーティングテーブルを出力すると、
Flags
にI
が含まれていることが確認できる
- ルーティングテーブルを出力すると、
$ netstat -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 192.168.211.254 UGScI 0 0 en1 127 127.0.0.1 UCS 0 0 lo0 127.0.0.1 127.0.0.1 UH 2 327379 lo0 ...
- netstatのドキュメントによると、
I
はRTF_IFSCOPE
を示すとのことI RTF_IFSCOPE Route is associated with an interface scope
- 説明はちゃんと理解できていないけど、そのインターフェース専用のgatewayとして設定されるということなのかな…
A route which is marked with the RTF_IFSCOPE flag is instantiated for the corresponding interface.
- いずれにしてもこれがあると都合が悪いので正常に戻したい
- 復旧手段
$ route -n get -ifscope en1 default route to: default destination: default mask: default gateway: 192.168.211.254 interface: en1 flags: <UP,GATEWAY,DONE,STATIC,PRCLONING> recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire 0 0 0 0 0 0 1500 0
- 削除〜追加のコマンドは、このような感じ(
en1
は各環境のインターフェース名にあわせる)
$ DEFAULT_GATEWAY=`route -n get -ifscope en1 default | grep gateway | awk '{ print $2 }'` $ sudo route delete default -ifscope en1 $ sudo route add default $DEFAULT_GATEWAY
- ルーティングテーブルを出力すると、
Flags
からI
がなくなっていることが分かる
$ netstat -nr Routing tables Internet: Destination Gateway Flags Refs Use Netif Expire default 192.168.211.254 UGSc 210 2 en1 127 127.0.0.1 UCS 0 0 lo0 127.0.0.1 127.0.0.1 UH 2 104 lo0 ...
それでは、快適なVPNライフをお過ごしください。
CVE-2015-4024.patch (PHP5.2/5.3)
今更感ではあるけれど、公式にはPHP5.4以降しか対応されなかったCVE-2015-4024のPHP5.2/5.3向けpatchを当時用意した。ソースを追った限りでは該当部分の実装はPHP5.2時代から変わっていなかったため、そのままバックポートしただけではある。
商用環境で数ヶ月稼働させて問題がないので、一応貼るだけ貼っておこうかなと思った。未だに何かの呪いでバージョンを上げられない環境はあるのだ。
CtrlP matcherをcpsmに変更する
Big Sky :: Vim の CtrlP matcher、cpsm がヤバイくらいに速すぎる を読んで、CtrlPのmatcherをcpsmに変更した。
インストールにはNeoBundleを使うけれど、インストール時にPythonモジュールのビルドが必要となるので、以下のように記述する。
.vimrc
NeoBundle 'nixprime/cpsm', { \ 'build': { \ 'others': 'sh install.sh' \}} let g:ctrlp_match_func = {'match': 'cpsm#CtrlPMatch'}
インストールでエラーが発生する場合には、ログの内容を確認する。
:NeoBundleLog
自分の環境では、このようなエラーが出力されていた。
... CMake Error at /usr/local/Cellar/cmake/3.2.2/share/cmake/Modules/FindBoost.cmake:1182 (message): Unable to find the requested Boost libraries. Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers. Call Stack (most recent call first): CMakeLists.txt:17 (find_package) ...
公式の Requirements をみると、確かに色々と必要であることが記載されているので、インストールされていないものは事前に準備しておく必要があるのであった。自分の場合は、エラーの内容からBoostが未導入だったので、Homebrewで追加した。
$ brew install boost
変更してすこぶる快適になった気分で使っていたけれど、一度アンインストールしてみても意外と遅くならなくて、プラシーボ効果だった気がしないでもない。とはいえ、遅くなるわけではないし、候補の選ばれ方も多少違うようなので、しばらく試してみる。
MEAN(mean.io)ではpassport-twitterが動作しない話
まとめ
MEAN(mean.io)ではpassport-twitterが(そのままでは)動作しないので、強引に回避するか諦めるかする必要がある。
何があったのか
MEAN(mean.io) を触っていたのだけれど、passport-twitterで認証すると下記のようなエラーが発生していた。
Error: Failed to find request token in session
よくあるミスで、localhost
にアクセスしているのに、Twitterのcallback URLは127.0.0.1
にしていてCookieが共有されていないという原因で発生しがちなエラーのようだけど、当然それも踏んだ上でまだ発生し続ける。
コンソールにエラー出力させてみると、別のエラーが原因でセッションからトークンが削除されているみたいだった。曰く、email
がないとのこと。
ValidatorError: Path `email` is required.
問題の箇所は、ログイン認証後にユーザ情報を格納する部分で、Mongooseのスキーマ上はemailフィールドは必須になっているけれど、Twitterの認証後処理にはemailを保存する処理が書かれていない。
これが実装ミスかというとそうでもなくて、Twitterのユーザ情報取得にはGET users/showを参照しているけれど、そもそもTwitter APIではメールアドレス情報は返ってこないので保存する項目に記載がないのはある意味で正しいとも言えるのだった。
つまり、MEAN(mea.io)のユーザ管理上はメールアドレスを必須としているけれど、メールアドレスを取得できないTwitterでは、認証連携はうまく動作しないということらしい。しれっと対応している風に実装されているけれど、確実に動作しないという罠であって5時間くらい潰れた。猫のうんこ踏め。
傾向と対策
Twitterでメールアドレスを取得する方法はないのかというと、残念ながら存在しない。
メールアドレスや電話番号の扱いについては、少なくとも直接公開されることはない旨がヘルプに記載されている。API経由での取得については数年前から要望には上がっていて、つい先日、許可されたアプリにのみaccount/verify_credentialsのオプションで取得が可能になったと公式からの告知があった。なんとなくヘルプの記載内容とは矛盾している気もするけれど。
いずれにしても、他のソーシャル連携と比較してスコープが雑なTwitterでは、現状の仕様のままメールアドレスが取得できるようにはならないだろうし、なったら危険な感じはする。
アプリケーションの要件にもよるけれど、MEAN(mean.io)のユーザ情報で何故メールアドレスが必要かといえば、パスワード紛失時の再発行などの用途以外で必須とする理由はあまりない(内部的にはユーザをユニークに特定するために使っているけれど、これはメールアドレス変更などを考えると若干筋が悪い気もする)。他サービス連携においては、パスワード紛失などは書くサービスに任せればよいので、単純にこの必須条件を外してしまってもよいとも思ったけれど、どこで参照しているかチェックするのも面倒だったので、ダミーの値を捏造して格納するようなことを考えた。
根本的には、アプリ自体をメールアドレス必須でなくして、メールアドレス取得可能なほかサービスでも不要な情報を保存しないようにするべきではあるのだろうなあ。
とりあえずの対応
実はこの問題、以前にIssueにも上がっていたようなのだけれど、議論が中途半端なまま半年くらいが経過して閉じられてしまっている。
回避派の人のだいたい考えることは同じで、必須条件を外すかダミーの値を生成するような感じである。ドメイン部分以外はほぼ同様で、ダミーの値をこういう感じに生成するようにして回避した。解決した気分じゃない。
user = new User({ name: profile.displayName, username: profile.username, email: profile.username + '_twitter@example.com', // この行を追加 provider: 'twitter', twitter: profile._json, roles: ['authenticated'] });
最近のVimFilerの挙動変更への対応
いくつか変更点があって、意図しない挙動ではなくなったので対応した。
VimFilerからファイルを選択しても新しいbufferで開かれなくなった
-quitオプションの名前が変わって-force-quitになったらしいので変更した。(4ca27f4)
- nnoremap <silent> ,vf :<C-u>VimFilerBufferDir -split -simple -winwidth=30 -quit<CR> - nnoremap <silent> ,vp :<C-u>VimFiler -project -split -simple -winwidth=30 -quit<CR> + nnoremap <silent> ,vf :<C-u>VimFilerBufferDir -split -simple -winwidth=30 -force-quit<CR> + nnoremap <silent> ,vp :<C-u>VimFiler -project -split -simple -winwidth=30 -force-quit<CR>
buftabsでバッファ一覧に表示されなくなった
あまり因果関係を理解していないけれど、g:vimfiler_restore_alternate_file のデフォルトが1になったことが影響している感じだった。(198eb0e)
+ let g:vimfiler_restore_alternate_file=0
git bisect便利。
momonga.vim #6でinside-motion.vimを作った
momonga.vim #6に参加してきた。
vimを本格的に使うようになってから2年足らずだけれど、Vim Scriptはちゃんと書いたことがなかったので、よい機会だと思ってもくもくすることにした。
そもそも基本文法からほぼ分からない状態だったので、Vimスクリプト基礎文法最速マスター - 永遠に未完成や、「実践Vim」を読んでみた感想と Vim script 初心者講座 | MBA-HACKなどを読みながら1時間くらい。なんとなく分かったところで何を作ろうか考えて、あまり効率よくできていない移動周りをよしなにしてくれるモーションプラグインを書こうと思った。
HTMLタグだったり関数呼び出しの引数部分だったりキーだったり、とかく中身だけ編集したいというシーンが結構多いのだけれど、fとかで毎回先頭文字を指定して移動するのがいけてないと思っていたので、そういう内側に一気に飛んでくれるためのプラグインが欲しかったのだった。(↓完成したスクリーンショット)
camelcasemotionのソースを中心にいろいろプラグインとかドキュメントを読んで書き始める。
NeoBundleでローカル環境のプラグインを読み込むにはどうすればよいのか悩んだけれど、NeoBundleLocalを使えばいける感じだったので、.vim/bundle下に直接ファイルを置いて開発することにした。
$ mkdir -p ~/.vim/bundle/inside-motion.vim && $_ $ mkdir plugin autoload $ touch README.md $ vim -c ':NeoBundleLocal ~/.vim/bundle'
既存プラグインを参考に大枠はだいたいできたものの、正規表現のエスケープがいつもの感覚と違うで変に時間を取られてしまった。検索するときは\vを使ってしまうけれど、プラグインでもカジュアルに使ってよいのか悩ましかったので、基本的には使わない方向でやろうと思った。他にはデフォルトのキーマップで迷ったり、一度githubにあげてインストールしてからローカルファイルを編集して反映されないとか悩んだりなどして時間が過ぎていった。
結局時間内にはすべて実装終えることができなかったので、日曜日のプリキュア観るつもりだった時間に残った作業をしてgithubにあげた。
Vim Scriptの書き方少し分かった気がするし、一応今回の目的は達成したような感じがする。 あとは、暗黒美夢王のライブが聴けたのはとてもよかった。4曲ってWake Up, Girlsよりも持ち歌が多い。