cloudfoundry

Cloud Foundry APIを使うために最初の認証の通し方


はじめに

夏休みの自由研究です。きっとこの記事を読んで業務で役に立ったり、身長が伸びたり、彼女ができたりすることは無いのですが、ぱっと見どこにも情報がなかったし、それなりに頑張ったので書く。

ちなみに、コミケ1日目に参加したらそこで謎の風邪をもらってきて、それからまるっと一週間寝込んでしまし私の夏休みはこの自由研究と、嫁に風邪をうつしたという実績のみで終了しました。死のう。


CloudFoundry、俺はお前のことが大嫌いだ

CouldFoundry使ってる人とか稀に時々いると思います。

大抵の場合cfコマンドとか使ってターミナルから操作を行うと思いますし、それで事足りるのですが、例えばbotからCloudFoundryを操作したいとき、特にCloudFoundry上に構築されたサーバ上で動いてるbotからCloudFoundryを操作したいときって、絶対そのサーバにcfコマンド入ってないじゃないですか! なんだよ! どうすりゃいいんだよ! 詰んでるよ!!


CloudFoundry API が用意されている

安心してください。CloudFoundry APIというやつが用意されています。

http://apidocs.cloudfoundry.org/

多分だけど、自信ないけど、cfコマンドの中身ってこのAPI叩いてるだけだと思うですよ。どうでしょう? どうなんでしょう?

さて、APIが用意されてるなら叩けばいいだけじゃーん。やったね。と思うけど、このドキュメント、ログインの仕方について、どこにも書いてなくね? 詰む。


なので、調べた

この記事の本題です。ログインtoken取れたらあとはすきに使えるので、tokenのとり方について調べました。

cf-client という npmモジュールがあって、最初はこれを使おうと思ったのですが、最後の更新が2年前だし、インストールすると依存関係にある他のモジュールが duplicatedだったり、脆弱性警告でたりして散々だったので使うことを断念。ただ、一応、動くので、ログインの部分の実装だけ参考にあとは自前で実装することにしました。


シーケンス

size 20  _TITLE_.png

雑だけど、無いよりはましということで書きました。図中のCloudFoundryAPIのURLは cf loginとかするときに指定するURLです。ココでは仮に api.cf.example.com としておきましょう。

大雑把な流れはこうです。



  1. api.cf.example.com/v2/info にアクセスして APIに関する情報を取る。

  2. ゲットした情報の中に authorization_endpoint というURLがあります。こいつがログインサーバのURLです。


  3. ${authorization_endpoint}/oauth/tokenというURLにアクセスしましょう。ここは罠がたくさんあります。

  4. token一式が返ってきます。acees_tokenをゲットできましたね! あとはAPIドキュメント みながらAPIが叩けるね!

という感じです。


前述の1, 2, 4は別に罠は無いです。いや、上のシーケンスが必要であることがAPIドキュメントのどこに書いてあるのかさっぱりわからんっていう罠はあるけど、大した罠じゃないです。それよりも3のtoken取得する部分が特大の罠があります。


罠1: authorization_endpoint にアクセスしても無意味

authorization_endpointはあくまでendpointであって、こいつに /oauth/tokenってパスを補ってあげないとダメっす。このAPIの情報ってどこにかいてあるのよさ……


罠2: Basic認証

${authorization_endpoint}/oauth/token はパスワード無しのBasic認証が必要です。

Authorizationヘッダに Basic Y2Y6 って書いて渡してあげる必要があります。

知るかそんなもん!


罠3: Content-Typeとpayload

Content-Typeは application/x-www-form-urlencodedをしていしましょう。

ペイロードにはgrant_type=password&client_id=cf&username=${username}&password=${password}

みたいなplain textを書きましょう。

僕は通信にaxiosを使ってるおかげで若干ハマりました。


まとめたコード(ざっくり)

const axios = require('axios');

axios.post(`${authorization_endpoint}/oauth/token`,
`grant_type=password&client_id=cf&username=${username}&password=${password}`,
{
headers: {
Authorization: 'Basic Y2Y6',
"Content-Type": 'application/x-www-form-urlencoded'
}
}
)
.then(res => {
console.log(res.data); // tokenが表示されるはず
});

こんな感じで無事tokenが取得できるのでした。


まとめと感想

Client Library書いた人たちは一体何のドキュメントを元にこういう処理を書いたのか謎ですが、まぁ動いたし、これ以上のことをやろうと思わないのでこれはこれでOKかなと思います。

苦労して作った機能のわりに、実際にbotに組み込んでみたら「あ、なんか全然いらん機能をわしは作り込んでしまったっぽよい」という気持ちになって、死のうと思いました。

超余談ですが、お盆休み中はあくまでただのお盆休みなので、休日診療所が空いて無いのですね。各自治体の医師会のホームページなんかを見ると診療所がいつ休みで、いつ診療してるかの一覧があったりするのでおすすめです。私の場合は家の付近で空いていたのがヤブ医者疑惑のあるおじいちゃん先生の診療所だけだったのですが、わらにもすがる思いでおじいちゃん先生のところに行ったら、抗生物質を処方してくれて熱は下がったのですが未だに咳が止まりません。きつい。

現場からは以上です。もっと有益なコードになる予定だったのになぁ……