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

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

前回に続いてWindows Live ID SDKよりWindows Live ID Delegated Authentication(委任認証)です。前回は、ユーザーに対して承認の要求処理までを紹介しました。今回は承認情報の受信処理についてです。

承認要求ページと承認管理ページ

はじめにユーザーが目にする承認要求ページについて確認しておきましょう。Webサイト(アプリケーションプロバイダ)が示した承認要求ページのリンクをクリックすることでユーザーは承認要求ページ図1に移動します。

図1 承認要求ページ
図1 承認要求ページ

承認要求ページでは、アプリケーションプロバイダが要求したオファーおよびアクションに対してアクセスの許可ができます。一度許可を行い再び承認要求ページへ移動した場合は、既に許可したその許可がまだ有効な期間にあるオファーおよびアクションについては表示されません。ページへ移動したときすべて有効なオファーおよびアクションであった場合は、すぐにアプリケーションプロバイダの戻り先URLへリダイレクトされます。

ユーザーがアクセス許可を取り消したい場合は、承認管理ページ図2で行います。

図2 承認管理ページ
図2 承認管理ページ

承認情報の受信

それでは、承認要求ページからリダイレクトされたときの処理を説明します。承認サービスは戻り先URLにHTTP POSTにより承認情報を返します。戻り先のページでは次の4個のパラメータが含まれているかを確認し処理する必要があります。

ResponseCode

承認要求の状態を表す応答コードです。次のいずれかが格納されています。

説明
RequestApproved ユーザーは承認要求プロセスを完了
RequestRejected ユーザーは承認要求プロセスをキャンセル

アプリケーションプロバイダが要求した許可に対して、すべてまたは一部を許可した場合に「RequestApproved」の文字列が格納されています。

ConsentToken

承認トークンです。承認要求を完了した場合のみ返されます。このトークンにはさらに複数のパラメータが含まれています。アプリケーションプロバイダはこの情報を使用してリソースプロバイダにアクセスします。構造の解析はこの後説明します。

action

ユーザーの実行中の操作を表す文字列が格納されています。現在のところ格納される可能性がある値は次のひとつのみです。

説明
delauth ユーザーが承認要求のプロセス完了に成功
appctx

承認の要求時に指定したappctxパラメータの値が格納されています。

ResponseCodeの値が「RequestApproved」の場合、ConsentTokenに格納されている承認トークンの解析処理に進みます。

委任認証プロセスにおいて必須の処理の中で、ここだけPOSTデータを処理する必要がありJavaScriptのみでの利用が不可能になっています。

承認トークンの構造

承認トークンの文字列は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>

承認の更新

承認トークン内に含まれていた委任トークンは、リソースプロバイダと通信する際に必要になります。そのユーザーデータへ実際にアクセスする方法は、次回以降に紹介します。ここでは先に承認を更新する方法を紹介します。

通常は取得した委任トークンをアプリケーションプロバイダが保存しておき、ユーザーデータへアクセスする際に使用しますが、委任トークンには有効期限があります。ユーザーがオファーとアクションに対して承認した有効期限よりも短く、数時間程度が有効期限として設定されているようです。委任トークンは承認トークンに含まれていた更新トークンを使用して新たに有効な委任トークンを取得できます。これを承認の更新と呼び、この更新方法を説明します。

新しい委任トークンを取得するには、次の承認サービスの承認更新用のURL「https://consent.live.com/RefreshToken.aspx」に必要なパラメータを指定してアクセスします。承認要求と似た操作になりますが、大きく次のふたつの点で異なります。

  • ユーザーの操作(承諾など)がない

  • JSON(JavaScript ObjectNotation)形式で情報が返ってくる

承認要求では、ユーザーがアクセス許可を行う承認要求ページに移動しユーザーの操作が必要でしたが、委任トークンの更新ではアプリケーションプロバイダとWindows Live ID承認サービスとの間でのみ完了し、ユーザーの操作は必要ありません。また、承認要求の情報はPOSTデータとして承認サービスより取得していましたが、委任トークンの更新では承認更新用のURLへアクセスし、その応答にJSON形式のデータを受け取ります。

以上のように更新処理はJavaScriptのみを使用したやり取りが可能になり、アプリケーション設計においての利便性が考えられますが、実際にはアプリケーション登録(アプリケーションIDを取得)をしていない場合、更新トークンが取得できなかったり、登録している場合は更新情報の復号化処理が必要であったりとあまり利便性はないように思います。

さて、承認更新用のURLのパラメータには次のものを指定します。前回の記事にて紹介した承認の要求時に使用したパラメータと同じものもあります。併せて確認してください。

ru

更新された委任トークンを受け取るURL指定します。URLは完全修飾のドメイン名(例: www.gihyo.jp)を使用し、クエリ文字列のパラメータが含まれていてはいけません。このパラメータはアプリケーション登録がされている場合、省略できます。

ps

アプリケーションプロバイダが必要とする許可(オファーとアクション)を表す文字列を指定します。

reft

更新トークンを指定します。今回紹介した承認情報の取得にて得られた承認トークンに含まれている更新トークンと呼ばれる文字列を指定します。

app

アプリケーション検証トークンを指定します。これは承認要求のときにも指定したものです。アプリケーションが登録してありアプリケーション検証を必須に設定してある場合にこのパラメータが必要になります。アプリケーション検証トークンの作成方法は前回紹介しています。

承認更新情報の受信

承認の更新時、承認サービスからはJSON形式の値が応答されます。値は次のいずれかが格納されています。

ConsentToken

承認トークンです。構造は先に示したものと同じです。有効な期限付きの委任トークンが含まれています。実際にはJSON形式のため次のような形式の文字列として取得されます。

{"ConsentToken":"eact%3D…"}
error

承認更新時に何らかのエラーが発生した場合は、そのエラー内容を示す番号が返ってきます。例えば次のような文字列です。

{"error":"2000"}

エラー番号の内容は、MSDNライブラリ内のエラーコードを参照してください。

次に承認更新を行うVB.NET(ASP.NET)のコード例を示します。ページ中に承認サービスより返ってきたJSON形式の文字列を表示するだけのコードになります。実際のアプリケーションでは、委任トークンの有効期限が切れていた場合、更新トークンを用いて委任トークンを更新するという処理が必要になります。

' Imports System.Net
Dim ps As String = "SpacesPhotos.ReadWrite,ContactsSync.FullSync,ApplicationStorage.ReadWrite"
Dim reft As String = HttpUtility.UrlDecode("更新トークン")
' GetAppVerifierToken, GetTimestamp メソッドは前回の記事を参照
Dim app As String = GetAppVerifierToken("****Application ID****", "****SecretKey****", GetTimestamp)

Dim path As String = String.Format("https://consent.live.com/RefreshToken.aspx?ps={0}&reft={1}&app={2}", ps, reft, app)
Dim req As HttpWebRequest = DirectCast(WebRequest.Create(path), HttpWebRequest)

Try
    Dim json As String
    Using response As HttpWebResponse = DirectCast(req.GetResponse, HttpWebResponse), _
          stream As New System.IO.StreamReader(response.GetResponseStream)
        json = stream.ReadToEnd
    End Using
    Response.Write(json)

Catch webEx As WebException
    Response.Write(webEx.Message)
Catch ex As Exception
    Response.Write(ex.Message)
End Try

サンプルコード

最後に委任認証のサンプルコードについて紹介しておきます。Windows Live IDDelegated Authentication SDK 1.0という各種言語を使用した委任認証のサンプルコードが提供されており、ダウンロードセンターからダウンロードができます。C#、Java、Perl、PHP、Python、Rubyのコードが用意されています。各サンプルの実行は、MSDNライブラリ内の委任認証のサンプルを参照してください。認証部分はライブラリとして使用できるようにサンプルページと分離されています。また、サンプルは委任認証以外にWeb認証と呼ばれるWindows Liveサービスも使用しています。すこしわかりにくいかもしれませんが、暗号・復号化部分など参考になると思います。


委任認証については今回でおわりです。委任認証の使い方は理解いただけたでしょうか。前回と今回の内容だけではアプリケーションとしてはまだ何もできません。次回から委任認証を利用してWindows Live サービス上のユーザーデータにアクセスしてみたいと思います。

おすすめ記事

記事・ニュース一覧