まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

タグ:oauth

IBM Bluemix の利用料金は Bluemix ログイン後にアカウントメニューの「使用状況ダッシュボード」から確認することができます:
2016120801


組織とデータセンターの地域を指定して課金対象を絞りこむことができます。以下は月毎の推移グラフ:
2016120802


下にスクロールすると現在の月の、現時点での消費額を確認することもできます:
2016120803


さて、これらは利用料金を Bluemix のウェブコンソールにログインした上で確認する、という手順です。この内容を Bluemix のウェブコンソールを使わずに API で取得する方法は・・・ ありました!以下に Billing API を使って外部から利用料金を確認する手順を紹介します。

Billing API を実行する上で、以下の情報を指定する必要があります:
(1) 対象組織の GUID
(2) 対象地域(データセンター)
(3) 対象年月(YYYY-MM)
(4) OAuth トークン

(2) と (3) は指定するだけですが、(1) の組織 GUID と (4) の OAuth トークンはあらかじめ調べておく必要があります。仮に (2) はアメリカ南部("us-south")、(3) は 2016-11 を指定するものと仮定しておきます。


(1) の GUID は cf ツールを使って調べます。まずは利用料金を調べたい地域の API サーバーに cf ツールでログインします(下の例では US データセンターを指定しています):
$ cf login -a https://api.ng.bluemix.net/ -u (ユーザーID)

対象とする組織の名称(ID)がわかっている場合は不要ですが、組織 ID を確認する場合は "cf orgs" コマンドを実行します。ログインした ID で利用中の組織 ID の一覧が表示されます:
$ cf orgs

組織 ID が確認できている場合は、以下のコマンドでその組織の GUID を取得できます:
$ cf org (組織ID) --guid


次に (4) の OAuth トークンを取得します。これは同様に cf ツールで "cf oauth-token" コマンドを実行します。すると "bearer " から始まるトークン文字の羅列が戻ってきます。これが OAuth トークンです:
$ cf oauth-token
bearer XXXXXXXXXX....(文字の羅列)....XXXXXXXXXX

これで (1), (2), (3), (4) 全ての情報が揃いました。これらの情報を使って目的月(今回は 2016-11)の利用料金をコマンドラインから調べてみます。実行コマンドと、その実行結果(の一部)は以下のようになります:
$ curl -v -X GET -H "Authorization: bearer (OAuth トークン文字列)" "https://rated-usage.ng.bluemix.net/v2/metering/organizations/us-south:(組織 GUID)/usage/2016-11" | python -m json.tool

{
  "organizations": [
    {
      "billable_usage": {
        "spaces": []
      },
      "country_code": "JPN",
      "currency_code": "JPY",
      "id": "********-****-****-****-************",
      "name": "dotnsf@jp.ibm.com",
      "non_billable_usage": {
        "spaces": [
          {
            "applications": [],
            "containers": [],
            "id": "********-****-****-****-************",
"name": "********-****-****-****-************",
"services": [ { "id": "********-****-****-****-************",
"instances": [ { "id": "********-****-****-****-************",
"name": "IBM Insights for Twitter-5b", "plan_id": "********-****-****-****-************",
"usage": [ { "applicationId": "********-****-****-****-************",
"cost": 0, "name": "dotnsf-php-20161026", "quantity": 22066, "unit": "TWEET", "unitId": "TWEETS_PER_MONTH" } ] } ], "name": "twitterinsights" } ] }, { "applications": [ { "id": "********-****-****-****-************",
"name": "dotnsf-cloudant", "usage": [ { "buildpack": "********-****-****-****-************",
"cost": 2557.8000000000002, "quantity": 348, "runtime": { "id": "********-****-****-****-************",
"name": "liberty-for-java_v3_2-20160822-2200" }, "unit": "GB-HOURS", "unitId": "GB_HOURS_PER_MONTH" } ] }, : :

青字部分が実行コマンドで、その下が実行結果です。実行結果のところどころに "cost": ***** という形で各ランタイムやサービスごとの料金が表示されていることがわかります。

というわけで、この API を使うことで Bluemix の利用料金をコマンドラインから参照する、ことが実現できそうです。


(参考)
http://theblasfrompas.blogspot.jp/2016/02/invoking-billing-api-for-bluemix-public.html

久しぶりに Twitter API キーやアクセストークンを新規に取得しようとしたら、それまで知っていた手順と違っていたので、改めて書き残しておきます。

まず以下のサイトへ行きます。ログインしていない場合は右上に "Sign in" というリンクが表示されるので、そこからログインします:
Twitter Application Management


Twitter Application Management サイトにログインすると、自分が過去に作った Twitter アプリの一覧が表示されます(まだ作ったことがない場合は何も表示されないはずです)。新たに API キーを取得するには新しいアプリを1つ定義します。画面右上の "Create New App" と書かれたボタンをクリックします:
2015111101


新規に作成するアプリケーションの概要を入力します。このうち "Name" はアプリケーションの名称ですが、全半角スペースを含むことができません。また、既に誰かが使っている名称を使うこともできません。1語の単語の形でユニークな名称を指定してください。"Description" はアプリケーションの説明文ですが、空にはできません。"WebSite" はアプリケーションのウェブサイト URL でこれも必須ですが、Streaming API などウェブサイトの存在しないアプリを作る場合もあると思います。ここは http://127.0.0.1 で始まるような名前を指定しても動作には支障なさそうでした。Callback URL は OAuth のコールバック先ですが、必須ではありません:
2015111102


全て入力したら下にスクロールして、Developer Agreement を確認し、内容に同意できる場合は "Yes, I agree" にチェックを入れて、最後に "Create you Twitter application" ボタンをクリックします:
2015111103


指定したアプリケーションの API キーが作成されます。API キーを確認するには、"Keys and Access Tokens" タブを開くと、その中に API Key や API Secret などが表示されているはずです:
2015111104


一方、アクセストークンはこの段階ではまだ作成されていないはずです。アクセストークンが必要な場合はこのページを下にスクロールして、まだ作成されていないことを確認した上で "Create my access token" ボタンをクリックします:
2015111101


処理が成功すると同ページの内容が書き換わり、アクセストークンとアクセストークンシークレットが確認できるようになります:
2015111102



以前の方法だと、最初は https://dev.twitter.com/ からスタートしたような記憶があるんだけど、今はそこからだと API Key 取得ページへのリンクが見当たらないんだよな、、変わったのかな?


IBM のパブリック PaaS サービスである Bluemix を利用する上では、まず IBM ID ※と呼ばれるアカウントを取得する必要があります。そして IBM ID とパスワードでサービスにログインすることで、各種インスタンスを生成したり、設定変更したり、・・・というオペレーションが可能になります。

※正確には「Bluemix 用の IBM ID」と言うべきだと思ってます。


この IBM ID を自分のアプリケーションの認証として使うことができれば、わざわざユーザーディレクトリを別途用意する必要がなく、アプリケーションを「IBM ID でログインして使う」ということが可能になります。またこれができれば、例えば2つの異なるアプリケーションで共通のユーザーディレクトリを使いたい時にも、2つのユーザーディレクトリを用意する必要がなく、IBM IDという共通のアカウントを使えば(そしてアプリケーションの認証を IBM ID を使って実装すれば)できちゃうことになります。PaaS の環境にこのようなユーザーディレクトリまで用意されているのは便利ですね。 というわけで、今回は Bluemix 環境で SSO サービスを使ったアプリケーションを開発する方法の紹介をします。

まず(普通に)IBM IDで IBM Bluemix 環境にログインし、アプリケーションを1つ作成します(このアプリケーションで SSO サービスを使うことになります)。ここでは bluemixsso.mybluemix.net というホスト名でアプリケーションサーバーを作成しています。
2014071401a


そしてこのアプリケーションに SSO サービスをバインドします。ここまではデータベースサービスをバインドするような手順と同じです。
2014071401b

Single Sign On サービスを選択して、作成したアプリケーションにバインドします:
2014071401c


次に SSO サービスを REST API で使うためのエンドポイントを確認します。アプリケーションのページを開いて、その内の Single Sign On サービスパーツの "Show Credentials" をクリックします。
2014071403


このようなテキストフィールドが開いて、JSON テキストが表示されます:
2014071404


ここで表示される JSON テキストは以下のようになっています。この赤字部分(authorize_url, token_url, profile_resource の3つの値)を後で使うのでメモしておきます:
{
  "single.sign.on" : [ {
    "name" : "Single Sign On -5q",
    "label" : "single.sign.on",
    "plan" : "beta",
    "credentials" : {
      "profile_resource" : "https://idaas.ng.bluemix.net/idaas/resources/profile.jsp",
      "tokeninfo_resource" : "https://idaas.ng.bluemix.net/idaas/resources/tokeninfo.jsp",
      "openidProviderURL" : "https://idaas.ng.bluemix.net/idaas/openid",
      "token_url" : "https://idaas.ng.bluemix.net/sps/oauth20sp/oauth20/token",
      "authorize_url" : "https://idaas.ng.bluemix.net/sps/oauth20sp/oauth20/authorize"
    }
  } ]
}

次に SSO の Credential 情報を設定します。同じ画面の左ペインから "SERVICES" - "Single Sign On" をクリックします。画面右に現在の(初期状態の)SSO の設定内容が編集可能な状態で表示されます:
2014071405


以下のように編集して、最後に "Save" ボタンをクリックします:
 Identity Providers: "IBM" にチェック
 Authentication Protocol: "OAuth 2.0" を選択
 Display Name: ユーザーの画面に表示されるアプリケーション名称を指定
 Enabled: チェック
 Redirect URI: アプリケーションの OAuth リダイレクトURI (後述)を指定
2014071406


認証方法には OpenID か OAuth2.0 かを選ぶことができますが、今回は OAuth2.0 にしています。またその Provider に "IBM" を選ぶことで IBM ID を使った OAuth を指定していることになります。

入力内容に不備がなければ保存され、画面には "Client Identifier" と "Client Secret" という2つの値が表示されるはずです。この2つの値も後で(OAuth の認証時に)使うのでメモしておきます。
2014071407


ここまでの作業でサービス側の準備はできました。では次にこの SSO を実際に使って OAuth でログインするアプリケーションの実装方法を紹介します。なお、以下の例では Java および JavaScript を使って実装していますが、API そのものは REST を使うので他の言語でも同様の処理を記述すれば実装できると思います。

なお、今回はログイン後のページの URL(上記のRedirect URI) を http://localhost:8080/BluemixSSO/index.jsp として SSO で設定しています。あくまで localhost を使った開発環境での設定であり、本番稼働時にはここをhttp://bluemixsso.mybluemix.net/index.jsp という値に書き換える必要があります。ただ今回の紹介ではあくまで開発環境上だけでの稼働確認を行うためこの値にしています。適宜変更して利用してください。


まずはログイン前のページを用意します。ログイン後のページと同じページにしてもいいのですが、いろいろ面倒なのでログイン前は login.html、ログイン後は index.jsp というページが表示されるものとします。

で、ログイン前のページはこのような感じにします。このサンプルでは単純にログインボタンがあるだけです:
<html>
<head>
<title>ログイン前</title>
<script type="text/javascript">
var client_identifier = "(Client Identifierの値)";
//var client_secret = "(Client Secretの値)";
var server_url = "http://localhost:8080/BluemixSSO/index.jsp";
function login(){
  // authorize_url へリクエスト
  location.href = "https://idaas.ng.bluemix.net/sps/oauth20sp/oauth20/authorize?client_id=" + client_identifier + "&redirect_uri=" + server_url + "&scope=profile&response_type=code";
}
</script>
</head>
<body>
<input type="button" value="ログイン" onClick="login();"/>
</body>
</html>

このページ内のボタンをクリックすると JavaScript が実行されて、authorize_url に対してパラメータを付けてリクエストが実行されます。成功すると Redirect URL で指定した URL(http://localhost:8080/BluemixSSO/index.jsp) にアクセスコードが付与された形でリダイレクトされます。

そしてリダイレクト先(index.jsp)では以下の様なコードを用意しておきます:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<@ page import="javax.servlet.http.*" %>
<@ page import="java.util.*" %>
<@ page import="java.io.*" %>
<@ page import="java.net.*" %>
<@ page import="java.util.*" %>
<@ page import="org.apache.commons.httpclient.*" %>
<@ page import="org.apache.commons.httpclient.methods.*" %>

<% request.setCharacterEncoding("utf-8"); %>

<html>
<head>
<title>ログイン後</title>
<%
String client_identifier = "aDUvXmXYEFSGtnNgX7v1";
String client_secret = "6w3YoxVpdoZ0mp2Q41IA";
String server_url = "http://localhost:8080/BluemixSSO/index.jsp";

String code = request.getParameter( "code" );
String access_token = null;
String email = "";
if( code != null && code.length() > 0 ){
  //. アクセストークンを取得
  String req_url = "https://idaas.ng.bluemix.net/sps/oauth20sp/oauth20/token?client_id=" + client_identifier + "&client_secret=" + client_secret;
  String param = "grant_type=authorization_code"
      + "&redirect_uri=" + URLEncoder.encode( server_url )
      + "&code=" + code;
  try{
    HttpClient client = new HttpClient();
    PostMethod post = new PostMethod( req_url );
		
    post.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
    post.setRequestHeader( "Content-Length", "" + param.length() );
    post.setRequestBody( param );
		
    int sc = client.executeMethod( post );
    if( sc == 200 ){
      String body = post.getResponseBodyAsString();
      int n1 = body.indexOf( "\"access_token\":\"" );
      if( n1 > 0 ){
        int n2 = body.indexOf( "\"", n1 + 16 );
        if( n2 > n1 ){
          access_token = body.substring( n1 + 16, n2 );
					
          //. アクセストークンを使ってプロファイルデータを取得
          String req_url1 = "https://idaas.ng.bluemix.net/idaas/resources/profile.jsp";
          String param1 = "access_token=" + access_token;

          HttpClient client1 = new HttpClient();
          PostMethod post1 = new PostMethod( req_url1 );
						
          post1.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
          post1.setRequestHeader( "Content-Length", "" + param1.length() );
          post1.setRequestBody( param1 );
          int sc1 = client.executeMethod( post1 );
          if( sc1 == 200 ){
            String body1 = post1.getResponseBodyAsString();
            n1 = body1.indexOf( "\"email\":[\"" );
            if( n1 > 0 ){
              n2 = body1.indexOf( "\"", n1 + 10 );
              if( n2 > n1 ){
                email = body1.substring( n1 + 10, n2 );
              }
            }
          }
        }
      }
    }
  }catch( Exception e ){
    e.printStackTrace();
  }
}else{
	
}
%>
</head>
<body> 
<h1>ようこそ、<%= email %> さん!</h1>
</body>
</html>

index.jsp 内では2回 HTTP リクエストを発行しています。
まず1回目のリクエストでは code パラメータの値を受け取り、その値を指定してアクセストークンを取得しています。
次に2回目のリクエストでは取得したアクセストークンを利用して、ログインユーザーのプロファイルデータにアクセスし、その email アドレスを取り出しています。 ここまでの処理が成功していれば、HTML 部分の <h1> タグ内にそのメールアドレスの値が出力される、というものです。

この辺りの情報について、詳しくは SSO のドキュメントも参考にしてください:
Getting started with Single Sign On (BETA)


実際にこのようなアプリを作って動かしてみると、以下のようになります:

まずログイン前の login.html ページにアクセスします。これは静的なコンテンツなので誰がアクセスしても同じ「ログイン」ボタンだけが表示される画面になるはずです:
2014071408

この「ログイン」ボタンをクリックすると JavaScript が実行されてリダイレクト処理が行われます。その処理の中で IBM ID によるログインが行われます:
2014071409

もし未ログイン状態であれば IBM ID とパスワードを指定していログインしてください:
2014071410

このアプリを最初に使う場合のみ、アクセスコードの入力が求められます。以下の様な画面が表示されると同時に、IBM ID のメールアドレスにメールが送信されます。この例では "4232-" と書かれたテキストフィールドが表示されていますが、送信メールには 4232- で始まる数字4桁-数字6桁 の文字列が書かれているはずです。
2014071411

受け取ったメールの内容の数字6桁部分を書き足して SUBMIT ボタンをクリックします:
2014071412

内容が正しければ先へ進みます。このような処理を毎回繰り返したくない場合はこのブラウザを登録することで回避出来ます。その場合はこの画面で "Register this Device" にチェックを入れ、その下のテキストフィールドにデバイス名を入力(半角スペースは使えません)して「送信」ボタンをクリックします:
2014071413

そして最後に OAuth 認証時にお馴染みに「このアプリに権限を与えるか?」の確認画面が表示されます。チェックボックスにチェックを入れて "Approve" ボタンをクリックします:
2014071414

で、無事に権限の譲渡が行われ、アクセストークンを使ってプロフィールの取得が行われ、(この例では)メールアドレスを取得して画面に表示する、という処理を行うことができました。
2014071415


今回紹介した例はかなりシンプルで、単にログイン前とログイン後のページを分けて、ログイン後のページでログイン情報を表示する、というだけの処理を実装しています。 実際にはログイン前後のページを同じにしたいこともあるでしょうし、またログイン後にログイン情報を残したまま別のページに移動したい、ということもあるでしょう。それらの場合はセッション情報などを使ってステータス管理をしながら処理を記述していくことになると思います。その辺りは IBM Bluemix の SSO サービスに特化した話ではないので、ここでは割愛します。

とはいえ、この例でも分かるようにサードパーティでも IBM Bluemix 上で IBM ID によるログイン管理を行うアプリの開発が出来ることがわかりました。Cloud Foundry をはじめとする各種 PaaS 環境でも共有ユーザーディレクトリが提供されているのは珍しいので便利に使えそうです。

しかも、IBM Bluemix 環境での SSO サービスの利用は(少なくとも 2014/07/14 の時点では)無料だったりします:
2014071401
※IBM Bluemix の各種サービス価格の最新情報はこちらを参照してください:
 IBM Bluemix: Pricing Sheet


どこかのタイミングで有料化される可能性がないとは言えませんが、PaaS 環境で共有で使えるユーザーディレクトリのサービス自体が珍しく、嬉しいです。







このページのトップヘ