を作ったので公開しました。Viewに
<p><%= select_datetime Time.now, { :include_timezone => true } %></p> <p><%= select_datetime Time.now, { :include_seconds => true, :include_timezone => true } %></p> <p><%= select_timezone %></p>
のように書くと、
といったフォームが表示され、入力された値はconfig/environment.rbで設定されたタイムゾーン等に従って適当に変換されます。
ActiveRecordとの連携はこれでいいのですが、検索とかに使う場合はコントローラ側で値を取りだしたくなります。そのためのメソッドが、get_multiparameter_attributes()とget_multiparameter_time()です。 get_multiparameter_attributes()は、Multiparameter attributeを配列に変換します。
% script/console Loading development environment (Rails 2.3.5) >> params = { ?> :datetime => { ?> "label(1i)" => "2010", "label(2i)" => "1", "label(3i)" => "1", ?> "label(4i)" => "0", "label(5i)" => "0", "label(6i)" => "0", ?> "label(7i)" => "+0900" >> } >> } => {:datetime=>{"label(3i)"=>"1", "label(4i)"=>"0", "label(5i)"=>"0", "label(6i)"=>"0", "label(7i)"=>"+0900", "label(1i)"=>"2010", "label(2i)"=>"1"}} >> ActionController::Base.new.get_multiparameter_attributes(params[:datetime], "label") => [2010, 1, 1, 0, 0, 0, 900]
また、get_multiparameter_attributes()はdatetimeに限らず任意の Multiparameter attributeを配列に変換できます。変換ルールはActiveRecord::Baseのtype_cast_attribute_valueメソッドに準拠しています。
>> input1 = { ?> "test(1i)" => "10", "test(2)" => "string", "test(3f)" => "3.14", "test(4i)" => "3.14", ?> "test(5i)" => "g", "test(6f)" => "g", "test(7i)" => "1g", "test(8f)" => "3.14g" >> } => {"test(8f)"=>"3.14g", "test(1i)"=>"10", "test(2)"=>"string", "test(4i)"=>"3.14", "test(7i)"=>"1g", "test(5i)"=>"g", "test(6f)"=>"g", "test(3f)"=>"3.14"} >> ActionController::Base.new.get_multiparameter_attributes(input1, "test") => [10, "string", 3.14, 3, 0, 0.0, 1, 3.14]
get_multiparameter_time()はより直接的に、View内のselect_datetimeなどから得られた入力をRailsのTime型に変換した物を取得します。
% script/console Loading development environment (Rails 2.3.5) >> params = { ?> :datetime => { ?> "label(1i)" => "2010", "label(2i)" => "1", "label(3i)" => "1", ?> "label(4i)" => "0", "label(5i)" => "0", "label(6i)" => "0", ?> "label(7i)" => "+0900" >> } >> } => {:datetime=>{"label(3i)"=>"1", "label(4i)"=>"0", "label(5i)"=>"0", "label(6i)"=>"0", "label(7i)"=>"+0900", "label(1i)"=>"2010", "label(2i)"=>"1"}} >> ActionController::Base.new.get_multiparameter_time(params[:datetime], "label") => Fri, 01 Jan 2010 00:00:00 JST +09:00
注意点として、これらを使ってデータベース内のタイムスタンプ等を検索する場合、得られたTime型の変数をデータベース内で保存されるタイムゾーンに変換する必要があります。手元のRails 2.3.5+sqlite3という環境ではRailsのconfig.time_zoneの設定によらず、データベースに対してはUTCで保存されていたので、findを掛けるときにutcメソッドで変換する必要がありました。
ts = get_multiparameter_time(params[:search_keys], "timestamp").utc Log.find(:first, :conditions => ["ip_addr = ? AND recorded_at <= ?", params[:search_keys][:ip], ts, :order => "recorded_at DESC")
UTC以外のタイムゾーンに変更する場合は、in_time_zoneメソッドを使用します。
ts = get_multiparameter_time(params[:search_keys], "timestamp").in_time_zone('Tokyo')
引数に指定可能なタイムゾーン名は"rake time:zones:all"で調べることができます。
選択フォームの代わりにテキストフィールドを使う場合、Viewで
<%= text_field "search_keys", "timestamp_text" %>
とやっておいて
ts = DateTime.parse(params[:search_keys][:timestamp_text]).utc
携帯電話のいわゆる「かんたんログイン」機能における成りすまし問題について、アプリ編はあちこちで書かれているのでキャリア編を書いてみます。まず、問題の概略から。
仕組みとしては図の上のようになり、携帯サービスA,B,Cの全てに対して利用者aはxxxa、利用者bはxxxbという同じuidでアクセスすることになります。このため、
などの問題があり、サービス側だけでの完全な対策は厳しいと言えます。
そうした背景もあり、キャリアの方でできる対策はないかと考えたとき、ShibbolethというSSOで使われているStoredIDを応用すると多少は状況がましになるような気がしてきました。これをかんたんログイン機能向けにモディファイした方法を以下に述べます。
この方法では、キャリアゲートウェイが携帯からインターネットへのアクセス口とSSOにおけるIdP(認証サーバ)の役割を兼務します。また、端末から送信されてきたuid情報はすべて廃棄し、アクセスしてきた端末の回線情報から契約者のIDを生成して、それをuidとして送信します。フィールドとしては互換性を持たせるためにiモードID(HTTP_X_DCMGUID)、ez番号(HTTP_X_UP_SUBNO)、およびX_JPHONE_UID(HTTP_X_JPHONE_UID)を使っても良いですし、新しい X_****_TARGETED_UIDのようなフィールドにしても良いでしょう。
このフィールドでは以下のルールでuidが提供されます。
具体的なuidの例は図の下のようになります。利用者aが携帯サービスAにアクセスするとき、uidとして'xxxa'ではなく、'xxxaA'という値が渡されます。これは利用者aがサービスAにアクセスする時は必ず同じ値です。いっぽうでサービスBにアクセスした時は'xxxaB'、Cでは'xxxaC'というサイトごとに異なるuidが渡されます。利用者bも同様です。こうすることにより、サービスAの提供者に悪意があり、かつキャリアゲートウェイにも穴があって、これを介してサービスCに成りすましアクセスしようとしたとしても、オリジナルやサービスCにおけるuidが分からないため、Cのかんたんログイン機能は使えません。注意点として、uidの表現に必要な名前空間は既存の方法では利用者数分だけで済みましたが、この方法では利用者数×サービス数分が必要となります。
uidは例えば以下のキーを繋げた文字列のSHA-1ハッシュなどにします。
利用者識別子 現在の各社uid サービス識別子 各携帯サービスのサーバのfqdnまたはIPアドレス salt ランダムな文字列
おそらく今でも利用者の携帯電話から各サービスに渡すuidを求めるためにテーブルを引いているはずですから、そこにハッシュ関数を1段入れれば比較的容易に実現できそうな気がします。またStoredIDのように一度計算したハッシュをDBに保存すれば、時間のかかるハッシュ関数を使っていても2回目以降のアクセスではレスポンスを向上させることができるでしょう。
ただ、この方法でも信頼できるIdPとしてのキャリアゲートウェイのリストはどうしても必要になります。こうしたリストについては、キャリア側でhttpsなサーバ上にxmlファイルとかを提供してもらい、サービス提供者側は日に1回ぐらいクロールして随時更新する枠組みなどが欲しいところです。
この方法のメリットとしては、以下のようなものが考えられます。
逆に問題点もあります。
iPhoneによりキャリアとメーカの関係が変わったという話がありましたが、キャリアはいいかげん端末に関しては何でもありな状況を想定し、それでも耐えうる枠組みの構築を真剣に考え、早急に実行する必要があるのではないでしょうか。
.green. ====