使ってみよう! Windows Live SDK/API

第15回 Windows Live ID委任認証(2/2)

この記事を読むのに必要な時間:およそ 5 分

承認トークンの構造

承認トークンの文字列はURLデコードすると「delt=…&reft=…&skey=…&offer=…&exp=…&lid=…」のようにパラメータ名とその値のペアがアンパサンド(&)で区切られたクエリ文字列として構成されています。この文字列に含まれているパラメータは次のものがあります。格納されている値の使い方はこの後に説明します。

eact

暗号化された承認トークンです。アプリケーション検証トークンを指定した場合もしくはアプリケーション登録がされている場合は,承認トークンが暗号化されています。この値を復号すると次のパラメータがさらに格納されています。

delt

委任トークンと呼ばれる文字列です。アプリケーションプロバイダがリソースプロバイダに渡すトークンになり,リソースプロバイダはこのトークンを使用して承認情報を検証します。この委任トークンはすぐに有効期限切れになり使用できなくなります。

reft

更新トークンと呼ばれる文字列です。委任トークンの有効期限が切れた場合,承認を更新し,新たな委任トークンを取得するために使用するトークンになります。アプリケーション検証トークンを使用せずに承認トークンを受信した場合,この更新トークンがない場合があるようです。

skey

セッションキーと呼ばれる文字列になります。アプリケーションプロバイダはこの値を必要としません。

offer

ユーザーが承認したオファーとアクション,その有効期限が格納されています。例を以下に示します。

SpacesPhotos.ReadWrite:1249915138;ContactsSync.FullSync:1218985740;ApplicationStorage.ReadWrite:1249929098

オファーとアクションはピリオド(.)で結ばれ,その後ろにコロン(:)が付き1970年1月1日(UTC)からの経過秒として有効期限が表わされています。複数のオファーとアクションがある場合は,セミコロンで(;)で区切られています。

exp

委任トークンの有効期限が1970年1月1日(UTC)からの経過秒として格納されています。委任トークンの有効期限が切れた場合,更新トークンを使い新しい委任トークンの取得ができます。

lid

リソースプロバイダのユーザーデータの場所を表す識別子になります。当然ながらユーザーごとに異なり,この値によりユーザー個人のデータにアクセスできます。この値からユーザーのWindows Live IDアカウントは類推できません。

パラメータは以上です。承認トークンは,パラメータのeactがひとつだけ含まれている場合と,eactを除く各パラメータが含まれている場合の2種類になります。

承認トークンの復号化

アプリケーション検証トークンを使用した場合などPOSTデータに含まれている承認トークンが暗号化されている場合がありました。ここでは承認トークンの復号手順をコードで示します。言語はVB.NET(ASP.NET)を使用しています。

まずは利便性のために「delt=…&reft=…」のような形式の文字列をパラメータ名とその値のペアのコレクションに変換して返すメソッドを作ります。

Public Shared Function Parse(ByVal input As String) As Specialized.NameValueCollection
    Dim pairs As New Specialized.NameValueCollection
    Dim pairValues() As String = input.Split(New Char() {"&"c})

    For Each value As String In pairValues
        Dim separator As Integer = value.IndexOf("=")
        If separator = -1 OrElse separator = value.Length Then
            Continue For
        End If
        pairs(value.Substring(0, separator)) = value.Substring(separator + 1)
    Next
    Return pairs
End Function

復号にはAES(Rijndael)アルゴリズムを使います。キーサイズは128bit,共有キーはアプリケーション登録時に指定したシークレットキーから得られるバイト配列値を指定します。また,暗号化の処理のときデータブロックのバイト数が必要な数だけ満たしていないときに使用する埋め込み文字列の種類にはPKCS #7という方法を指定します。初期化ベクタには,暗号化されたトークンをURLデコードおよびBase64デコードして得られた先頭16バイトを指定します。

共有キーの作成は,アプリケーション検証トークンを作成するときに使用したDeriveメソッドを使用します。接頭辞に「ENCRYPTION」を指定します。以下のDeriveメソッドは前回のものと同一です。

' Imports System.Security.Cryptography
Public Shared Function Derive(ByVal secretKey As String, ByVal prefix As String) As Byte()
    Dim hashAlgorithm As New SHA256Managed
    Dim buffer() As Byte = System.Text.Encoding.Default.GetBytes(prefix & secretKey)
    Dim hashOutput() As Byte = hashAlgorithm.ComputeHash(buffer)

    Dim byteKey(15) As Byte
    Array.Copy(hashOutput, byteKey, byteKey.Length)
    Return byteKey
End Function

以上を踏まえた承認トークンを復号化するメソッドは次のようになります。例外処理は省略しています。

Public Shared Function DecryptToken(ByVal token As String, ByVal secretKey As String) As String
    Dim aesAlg As New RijndaelManaged
    aesAlg.KeySize = 128
    aesAlg.Key = Derive(secretKey, "ENCRYPTION")
    aesAlg.Padding = PaddingMode.PKCS7

    Dim ivAndEncryptedValue() As Byte = Convert.FromBase64String(HttpUtility.UrlDecode(token))
    Dim memoryStream As New System.IO.MemoryStream(ivAndEncryptedValue)
    Dim iv(15) As Byte
    memoryStream.Read(iv, 0, iv.Length)
    aesAlg.IV = iv

    Using cryptoStream As New CryptoStream(memoryStream, aesAlg.CreateDecryptor, CryptoStreamMode.Read), _
          streamReader As New System.IO.StreamReader(cryptoStream, System.Text.Encoding.ASCII)
        Return streamReader.ReadToEnd
    End Using
End Function

Webページ上に取得した承認トークンの各パラメータ値を表示するコードは次のようになります。

<div>
<%
    Dim consentToken As String = Request.Params("ConsentToken")
    If consentToken <> "" Then
        
        Dim pairs As Specialized.NameValueCollection = Parse(HttpUtility.UrlDecode(consentToken))
        For Each key As String In pairs.Keys
            Page.Response.Write(String.Format("{0}: {1}<br />", key, pairs(key)))
        Next
        
        If pairs("eact") <> "" Then
            consentToken = DecryptToken(pairs("eact"), "****SecretKey****")
        
            pairs = Parse(HttpUtility.UrlDecode(consentToken))
            For Each key As String In pairs.Keys
                Page.Response.Write(String.Format("{0}: {1}<br />", key, pairs(key)))
            Next
        End If
    End If
%>
 </div>

著者プロフィール

松江祐輔(まつえゆうすけ)

日本システムウエア株式会社 勤務。現在,ハードウェア設計・検証業務を担当。大学生・大学院生時代はベンチャー企業 有限会社ミレニアムシステムズにプログラマーとして従事。趣味はプログラミング。好きな言語はVisual Basic。Microsoft MVP for Windows Live Platform(Jul 2010 - Jun 2011),Windows Live(Jul 2011 - Jun 2013)。

URL:http://katamari.jp

コメント

コメントの記入