OpenIDでログインできるサイトを作成する2

今回も前回に続いて、DotNetOpenIdのOpenIdLoginコントロールについて説明します。

OpenIdLoginの外観に関するプロパティ

OpenIdLoginは、デフォルトでは、文字や説明が英語で表示されます。しかし、これらの文字列は変更可能ですので、日本語にすることもできます。

OpenIdLoginコントロールの外観に関するプロパティを以下にまとめてみました。なお、DotNEtOpenIdのヘルプはあまりに説明が足りないため、下の説明には私の推測が多く含まれていることをご了承ください。

名前説明
ButtonTextログインボタンに表示する文字列。デフォルトは"Login »"。
ButtonToolTipログインボタンのToolTipに表示する文字列。デフォルトは"Account login"。
ExampleUrlテキストボックスに入力するOpenID URLのサンプルとして表示する文字列。テキストボックスの下に表示される。デフォルトは"http://your.name.myopenid.com"。必要なければ、ExamplePrefixとともに空白にする。
ExamplePrefix"ExampleUrl"の前に表示する文字列。"ExampleUrl"はテキストボックスの下に表示される。デフォルトは"Example:"。
LabelTextテクストボックスの左に表示する文字列。デフォルトは"OpenID Login:"。
RegisterTextOpenIDアカウントを作成するページへのリンクの文字列。テキストボックスの下の右に表示される。デフォルトは"register"。
RegisterToolTipOpenIDアカウントを作成するページへのリンクのToolTipとして表示する文字列。デフォルトは"Sign up free for an OpenID with MyOpenID now."。
RegisterUrlOpenIDアカウントを作成するページへのリンクのURL。デフォルトは"https://www.myopenid.com/signup"。デフォルトのMyOpenIDは英語のサイトなので、openid.ne.jp("http://www.openid.ne.jp/index.php?action=register")などに変更した方がよいかもしれない*1
RegisterVisibleOpenIDアカウントを作成するページへのリンクを表示するかどうか。デフォルトはTrue。
RememberMe"Remember me"チェックボックスにチェックを入れるか。"Remember me"はテキストボックスに入力された文字列を覚えるのではなく、認証の状態をクッキーに保存することを意味しているようだ。具体的には、FormsAuthentication.RedirectFromLoginPageメソッドの2番目の引数にこの値を使用する。つまり、ほぼUsePersistentCookieプロパティと同じ。デフォルトはFalse。
RememberMeText"Remember me"チェックボックスに表示する文字列。デフォルトは"Remember me"。
RememberMeVisible"Remember me"を表示するかどうか。デフォルトはFalse。
ShowLogoテキストボックスにOpenIDのロゴを表示するか。デフォルトはTrue。
RequiredTextテキストボックスになにも入力しないでログインボタンが押されたときに表示する文字列。テキストボックスの下に赤字で表示される。デフォルトは"Provide an OpenID first."。
UriFormatTextテキストボックスに正しくない形式の文字列が入力されたときに表示する文字列。テキストボックスの下に赤字で表示される。正しい形式かどうかはIdentifier.IsValidメソッドで判断される。デフォルトは"Invalid OpenID URL."。
UriValidatorEnabledテキストボックスに正しくない形式の文字列が入力されたときに"UriFormatText"を表示するか。
ValidationGroupボタンのValidationGroupプロパティに設定する文字列。*2
IdSelectorIdentifierID Selectorを使用するとき、ハッシュ文字列を指定する。ID SelectorはOpenID URLの入力を補助するサービス。ID Selectorは海外のOpenIDプロバイダしか対応していないようなので、日本ではあまり使う意味がないだろう。
Columnsテキストボックスの幅。デフォルトは40。
CssClassテキストボックスのCSSクラス。デフォルトは"openid"。

ユーザーの個人情報を要求する

前号の例で見たように、ChoixのログインではOpenIDの認証の際に、OPでニックネームとメールアドレスを送信するかを聞かれました。このような個人情報のやりとりは、OpenID Simple Registration Extension(SREG)に従って行われます。OpenIdLoginコントロールでOPに個人情報の要求をするには、EnableRequestProfileプロパティをTrueにして(デフォルトでTrueです)、OpenIdLoginコントロールの"Request"で始まるプロパティの内、取得したい情報に該当するプロパティの値をRequestまたはRequireにします。

これらのプロパティにはDemandLevel列挙体の3つのメンバのうちどれかを指定します。NoRequestを指定すると、その項目は要求しません(デフォルトです)。Requestはオプションの項目であることを表し、ユーザー(あるいはOP)が拒否することができます(openid.sreg.optional)。Requireは必須項目であり、拒否された場合はRPでログインが失敗するかもしれないという項目です(openid.sreg.required)。

ただし、現時点ではSREGに対応していないOPが多いため、要求しても取得できないケースが多いです。

OPから返された個人情報は、OpenIdEventArgs.ResponseプロパティのGetExtensionメソッドでClaimsResponseオブジェクト(DotNetOpenId.Extensions.SimpleRegistration名前空間)として取得できます。

OpenIdLoginコントロールの"Request"で始まるプロパティには次のようなものがあります。

OpenIdLoginのプロパティ説明
RequestBirthDateユーザーの誕生日を取得するか(openid.sreg.dob)。
ClaimsResponse.BirthDateプロパティでDateTimeオブジェクトとして取得できる。
RequestCountryユーザーの国を取得するか(openid.sreg.country)。
ClaimsResponse.CountryプロパティでISO3166国コードの文字列として取得できる。日本ならば、"JP"。
RequestEmailユーザーの電子メールアドレスを取得するか(openid.sreg.email)。
ClaimsResponse.Email(文字列)とMailAddress(MailAddressオブジェクト)プロパティで取得できる。
RequestFullNameユーザーのフルネームを取得するか(openid.sreg.fullname)。
ClaimsResponse.FullNameプロパティで文字列として取得できる。
RequestGenderユーザーの性別を取得するか(openid.sreg.gender)。
ClaimsResponse.GenderプロパティでDotNetOpenId.Extensions.SimpleRegistration.Genderオブジェクトとして取得できる。
RequestLanguageユーザーの言語を取得するか(openid.sreg.language)。
ClaimsResponse.LanguageプロパティでISO639言語コードの文字列として取得できる。日本語ならば、"JA"。
RequestNicknameユーザーのニックネームを取得するか(openid.sreg.nickname)。
ClaimsResponse.Nicknameプロパティで文字列として取得できる。
RequestPostalCodeユーザーの郵便番号を取得するか(openid.sreg.postcode)。
ClaimsResponse.PostalCodeプロパティで文字列として取得できる。
RequestTimeZoneユーザーのタイムゾーンを取得するか(openid.sreg.timezone)。
ClaimsResponse.TimeZoneプロパティでTimeZone databaseの文字列として取得できる。例えば、"Asia/Tokyo"。

個人情報の送信を要求したときは、PolicyUrlプロパティ(openid.sreg.policy_url)も設定します(設定しなくてもよいですが、した方がよいでしょう)。PolicyUrlプロパティには、送信されたユーザーの情報をどのように使用するかを示したページ(プライバシーポリシーページ)のURLを指定します。

次の例(login.aspx)では、OpenIDでログインするとき、メールアドレスを必須項目、言語をオプション項目としてOPから取得を試みています。さらに、PolicyUrlプロパティも指定しています。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
<%@ Page Language="vb" %>
<%@ Register assembly="DotNetOpenId" namespace="DotNetOpenId.RelyingParty"
 tagprefix="RP" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
    
    'ログインしたとき 
    Protected Sub OpenIdLogin1_LoggedIn(ByVal sender As Object, _
                                        ByVal e As OpenIdEventArgs)
        'OPから返されたユーザーの個人情報を取得する 
        Dim claims As DotNetOpenId.Extensions.SimpleRegistration.ClaimsResponse = _
            e.Response.GetExtension( _
                Of DotNetOpenId.Extensions.SimpleRegistration.ClaimsResponse)()
        'メールアドレスと言語を覚えておく 
        Session("Email") = claims.Email
        Session("Language") = claims.Language
    End Sub
    
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <RP:OpenIdLogin ID="OpenIdLogin1" runat="server" 
            onloggedin="OpenIdLogin1_LoggedIn"
            RequestEmail="Require" 
            RequestLanguage="Request"
            PolicyUrl="~/PrivacyPolicy.aspx" />
    </div>
    </form>
</body>
</html>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
<%@ Page Language="C#" %>
<%@ Register assembly="DotNetOpenId" namespace="DotNetOpenId.RelyingParty" tagprefix="RP" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
 
    //ログインしたとき
    protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e)
    {
        //OPから返されたユーザーの個人情報を取得する
        DotNetOpenId.Extensions.SimpleRegistration.ClaimsResponse claims =
            e.Response.GetExtension
                <DotNetOpenId.Extensions.SimpleRegistration.ClaimsResponse>();
        //メールアドレスと言語を覚えておく
        Session["Email"] = claims.Email;
        Session["Language"] = claims.Language;
    }
    
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <RP:OpenIdLogin ID="OpenIdLogin1" runat="server" 
            onloggedin="OpenIdLogin1_LoggedIn"
            RequestEmail="Require" 
            RequestLanguage="Request"
            PolicyUrl="~/PrivacyPolicy.aspx" />
    </div>
    </form>
</body>
</html>

ここでは紹介しませんが、OpenIdLoginコントロールのプロパティを使用する以外に、次の項で紹介するIAuthenticationRequest.AddExtensionメソッドを使ってClaimsRequestオブジェクトを追加するという方法もあります。

認証ポリシーを要求する

OpenID Provider Authentication Policy Extension(PAPE)に従い、OPに認証ポリシーを要求することができます。OpenIdLoginコントロールで認証ポリシーを要求するには、PreferredPoliciesプロパティに適当なURI(文字列)が登録されたPolicyRequestオブジェクトを作成し、それをIAuthenticationRequest.AddExtensionメソッドで追加します。

認証ポリシーのURIは、AuthenticationPoliciesクラス(DotNetOpenId.Extensions.ProviderAuthenticationPolicy名前空間)に定義されているフィールドから取得できます。AuthenticationPoliciesクラスのフィールドには以下の3つがあります。

名前説明
MultiFactor複数要素認証
http://schemas.openid.net/pape/policies/2007/06/multi-factor
PhishingResistantフィッシング耐性認証
http://schemas.openid.net/pape/policies/2007/06/phishing-resistant
PhysicalMultiFactor物理的複数要素認証
http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical

認証ポリシーを要求しても実際にその通りに認証が行われるとは限りません。OPが認証時に使った認証ポリシーは、PolicyResponse.ActualPoliciesプロパティから取得できます。ActualPoliciesプロパティは認証ポリシーのURI文字列のコレクションになります。OPが認証ポリシーを一つも使用しなかった場合は、ActualPoliciesプロパティのコレクションに"none"という文字列が1つだけ登録されます。OPが全く対応していないときは、PolicyResponseがnullになります。

今のところ要求した認証ポリシー通りに認証を行うOPはかなり少ないです。その中でもPhishingResistantを行うOPはそこそこありますが、MultiFactorを行うOPはきわめて少ないです。

以下に、フィッシング耐性、複数要素、物理的複数要素を要求して認証を行うようにした例を示します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
<%@ Page Language="vb" %>
<%@ Register assembly="DotNetOpenId" namespace="DotNetOpenId.RelyingParty"
 tagprefix="RP" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
    
    'ログインする直前 
    Protected Sub OpenIdLogin1_LoggingIn(ByVal sender As Object, _
                                         ByVal e As OpenIdEventArgs)
        'PolicyRequestを作成する 
        Dim pr As New DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyRequest()
        '認証ポリシーを追加する 
        pr.PreferredPolicies.Add( _
            DotNetOpenId.Extensions.ProviderAuthenticationPolicy. _
                AuthenticationPolicies.PhishingResistant)
        pr.PreferredPolicies.Add( _
            DotNetOpenId.Extensions.ProviderAuthenticationPolicy. _
                AuthenticationPolicies.MultiFactor)
        pr.PreferredPolicies.Add( _
            DotNetOpenId.Extensions.ProviderAuthenticationPolicy. _
                AuthenticationPolicies.PhysicalMultiFactor)
    
        'OpenID Extensionを追加する 
        e.Request.AddExtension(pr)
    End Sub
 
    'ログインしたとき 
    Protected Sub OpenIdLogin1_LoggedIn(ByVal sender As Object, _
                                        ByVal e As OpenIdEventArgs)
        'OPが使用した認証ポリシーを覚えておく 
        Dim pr As DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyResponse = _
            e.Response.GetExtension( _
                Of DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyResponse)()
        If Not pr Is Nothing Then
            Session("ActualPolicies") = pr.ActualPolicies
        End If
    End Sub
    
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <RP:OpenIdLogin ID="OpenIdLogin1" runat="server" 
            onloggedin="OpenIdLogin1_LoggedIn"
            onloggingin="OpenIdLogin1_LoggingIn" />
    </div>
    </form>
</body>
</html>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
<%@ Page Language="C#" %>
<%@ Register assembly="DotNetOpenId" namespace="DotNetOpenId.RelyingParty" tagprefix="RP" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
 
    //ログインする直前
    protected void OpenIdLogin1_LoggingIn(object sender, OpenIdEventArgs e)
    {
        //PolicyRequestを作成する
        DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyRequest pr =
            new DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyRequest();
        //認証ポリシーを追加する
        pr.PreferredPolicies.Add(
            DotNetOpenId.Extensions.ProviderAuthenticationPolicy.
                AuthenticationPolicies.PhishingResistant);
        pr.PreferredPolicies.Add(
            DotNetOpenId.Extensions.ProviderAuthenticationPolicy.
                AuthenticationPolicies.MultiFactor);
        pr.PreferredPolicies.Add(
            DotNetOpenId.Extensions.ProviderAuthenticationPolicy.
                AuthenticationPolicies.PhysicalMultiFactor);
 
        //OpenID Extensionを追加する
        e.Request.AddExtension(pr);
    }
 
    //ログインしたとき
    protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e)
    {
        //OPが使用した認証ポリシーを覚えておく
        DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyResponse pr =
            e.Response.GetExtension<
                DotNetOpenId.Extensions.ProviderAuthenticationPolicy.PolicyResponse>();
        if (pr != null)
        {
            Session["ActualPolicies"] = pr.ActualPolicies;
        }
    }
    
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <RP:OpenIdLogin ID="OpenIdLogin1" runat="server" 
            onloggedin="OpenIdLogin1_LoggedIn"
            onloggingin="OpenIdLogin1_LoggingIn" />
    </div>
    </form>
</body>
</html>

OpenIdLoginコントロールのOpenIDに関するプロパティ

今まで紹介できなかったOpenIdLoginコントロールのプロパティを以下に列挙します。ここでの説明にも私の推測が多分に含まれていることをご了承ください。

名前説明
ImmediateModeopenid.modeをcheckid_immediateにするか、checkid_setupにするか。checkid_setupでは認証のために一度OPに飛んで再びRPに帰ってくるが、checkid_immediateでは基本的にはそのようなページ遷移を行わない。通常checkid_immediateはAJAXを使用して認証する場合に使われ、認証はIFRAMEやポップアップウィンドウを使って行う。checkid_immediateで失敗したときは、SetupRequiredイベントが発生し、checkid_setupで行う必要がある。デフォルトは、False。
RealmUrlopenid.realm(あるいは、openid.trust_root)に設定するURL。return_toのURLとマッチする文字列をワイルドカードを使って設定する。例えば、"http://*.dobon.net/"など。デフォルトは"~/"。
RequireSslOPとのやり取りをすべてHTTPSで行う。安全が確保できないときはOpenIdExceptionがスローされる。テキストボックスに入力されたOpenID URLの先頭が"http://"ならば"https://"に変更する(何もなければ、"https://"を付ける)。例えば、RequireSslをTrueとしたとき、OpenID URLを"yahoo.com"としたのでは成功せず、"me.yahoo.com"とすれば成功する。ヘルプの"RelyingPartySecuritySettings.RequireSsl Property"に詳細がある。この設定はWeb.configに記述することもできる。デフォルトは、False。
ReturnToUrlopenid.return_toとして指定するURL(ただし実際にはReturnToUrlに様々なパラメータを付加したURLをopenid.return_toとするようだ)。OPから戻る時の転送先のURL。空白(デフォルト)にすると現在のページのURLになるようだ。
Statelessstatelessモード(dumbモード)で行う。statelessモードでは共通鍵を保存しなくてよいが、OPとのやり取りが増える。デフォルトは、False。
CustomApplicationStore正直詳しくはわからないが、WebファームなどでHttpContext.Current.Applicationにデータを保存できないとき、その代わりとなる前のデータを保持する方法を提供するためのもののようだ。Web.configに記述することもできる。詳しくは、WebFarmHowto - dotnetopenid - How to implement OpenID in a multiple server situation.

RP discoveryを発行する

ここからはOpenIdLoginコントロールだけでなく、DotNetOpenIdライブラリ全体に関する話題になります。

今まで紹介してきたサンプルを使ってYahoo! USAをOPとして認証を行うと、次のような警告が表示されます(警告が表示されても認証はできます)。

Warning: This website has not confirmed its identity with Yahoo! and might be fraudulent. Do not share any personal information with this website unless you are certain it is legitimate.

これは作成したRPが、OpenID Authentication 2.0の仕様書にある「13.Discovering OpenID Relying Parties」に対応していないからです。(ただし、RP discoveryをチェックしているOPは少なく、RP discoveryに対応しているRPも少ないようです。)このRP discoveryというのは、RPが指定した"return_to"が正しいURLかをOPが検証するために使われます。

RP discoveryの発行は、Yadisプロトコルで行います。

実際にRPを改造してRP discoveryに対応してみましょう。まずは、発行するXRDSドキュメントを作成します。ここの<URI>要素に"return_to"とマッチするURLを指定します(ワイルドカードは使用できません)。OpenIdLoginコントロールの場合は、return_toを指定するプロパティであるReturnToUrlがデフォルトのままであれば、<URI>にはOpenIdLoginコントロールのあるページのURLを指定します。複数のページにOpenIdLoginコントロールがある場合は、<URI>要素を複数追加します。

また、ContentTypeを"application/xrds+xml"とする点にも注意が必要です。

以下に例を示します。なおこのコードは、"xrds.aspx"というファイル名で保存したものとします。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
<%@ Page Language="vb" ContentType="application/xrds+xml"
 %><?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
    <XRD>
        <Service xmlns="xri://$xrd*($v*2.0)">
            <Type>http://specs.openid.net/auth/2.0/return_to</Type>
            <URI><%=New Uri(Request.Url, _
                Response.ApplyAppPathModifier("~/login.aspx"))%></URI>
        </Service>
    </XRD>
</xrds:XRDS>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
<%@ Page Language="C#" ContentType="application/xrds+xml"
 %><?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
    <XRD>
        <Service xmlns="xri://$xrd*($v*2.0)">
            <Type>http://specs.openid.net/auth/2.0/return_to</Type>
            <URI><%=new Uri(Request.Url,
                Response.ApplyAppPathModifier("~/login.aspx"))%></URI>
        </Service>
    </XRD>
</xrds:XRDS>

次に、OPがXRDSドキュメントの場所を知ることができるように、RPが"realm"としたURLで<meta>要素またはHTTPレスポンスヘッダによりXRDSドキュメントのURLを指定します。<meta>要素を使用する場合は、

  1
<meta http-equiv="X-XRDS-Location" content="http://localhost/xrds.aspx"/>

のような記述をHTMLのヘッダに書き加えます("http://localhost/xrds.aspx"がXRDSドキュメントの場所です)。

HTTPレスポンスヘッダを使用する場合は、HTTPレスポンスヘッダに"X-XRDS-Location"を追加し、XRDSドキュメントのURLを指定します。

これらはDotNetOpenIdライブラリで用意されているXrdsPublisherコントロールを使えば簡単にできます。XrdsUrlプロパティにXRDSドキュメントのURLを指定します。また、XrdsAdvertisementプロパティでHTTPレスポンスヘッダとHTMLの<meta>のどちらを使うかを指定します。XrdsAdvertisementプロパティをBothにすると、HTTPレスポンスヘッダとHTMLの<meta>の両方に出力します。デフォルトはHttpHeaderで、HTTPレスポンスヘッダだけに出力されます。

OpenIdLoginコントロールの場合、"realm"を指定するRealmUrlプロパティのデフォルトは"~/"ですので、RealmUrlプロパティを変更していないのであれば、Default.aspxにXrdsPublisherコントロールを配置します。

Default.aspxにXrdsPublisherコントロールを配置した例を以下に示します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
<%@ Page Language="vb" %>
 
<%@ Register assembly="DotNetOpenId" namespace="DotNetOpenId" tagprefix="openid" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
    <openid:XrdsPublisher ID="XrdsPublisher1" runat="server"
        XrdsUrl="~/xrds.aspx" XrdsAdvertisement="Both">
    </openid:XrdsPublisher>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:LoginName ID="LoginName1" runat="server" />
        <asp:LoginStatus ID="LoginStatus1" runat="server" />
    </div>
    </form>
</body>
</html>
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
<%@ Page Language="C#" %>
 
<%@ Register assembly="DotNetOpenId" namespace="DotNetOpenId" tagprefix="openid" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<script runat="server">
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
    <openid:XrdsPublisher ID="XrdsPublisher1" runat="server"
        XrdsUrl="~/xrds.aspx" XrdsAdvertisement="Both">
    </openid:XrdsPublisher>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:LoginName ID="LoginName1" runat="server" />
        <asp:LoginStatus ID="LoginStatus1" runat="server" />
    </div>
    </form>
</body>
</html>

これでYahoo!の警告が消えたはずです。

OPのブラックリスト、ホワイトリストを設定する

「このOPは信頼できないから、このOPは常に拒否したい」という場合は、そのホスト名をブラックリストに登録することができます。ホスト名をブラックリストに入れるには、静的クラスであるUntrustedWebRequestクラス(DotNetOpenId名前空間)のBlacklistHostsプロパティを使います。BlacklistHostsプロパティは文字列のコレクションですので、Addメソッドで追加できます。BlacklistHostsプロパティに登録されているホスト名とOPのホスト名が一致した場合はエラーとなり、OpenIdLoginコントロールではFailedイベントが発生します。

BlacklistHostsプロパティに登録されるホスト名は、OpenID URLのホスト名と完全に一致していなければならないようです。例えば、"hogehoge.com"というホスト名を登録した場合、OpenID URLが"http://hogehoge.com/username/"であれば引っ掛かりますが、"http://username.hogehoge.com/"であれば引っかからずに認証が行われてしまいます。

"hogehoge.com"で終わるホスト名をすべて拒否したいのであれば、BlacklistHostsRegexプロパティを使うのがよいでしょう。このプロパティには正規表現のパターンを登録し、OPのホスト名が登録されているパターンとマッチすれば、拒否します。

ホワイトリストへの登録も同様で、WhitelistHostsプロパティとWhitelistHostsRegexプロパティが用意されています。

ブラックリストで引っかかってもホワイトリストに登録されていれば認証が行われるのかと思ったのですが、試した限りではそうではないようです。ブラックリストに引っ掛かれば、ホワイトリストに関係なく、拒否されます。

ヘルプによると、ホワイトリストに登録されていればスタンダードセキュリティチェックにパスしなくても許可されるということです。スタンダードセキュリティチェックというのがどういうのもなのか具体的には分かりませんが、"localhost"や"127.0.0.1"はこのチェックに引っ掛かるようです。よってローカルのOPでテストする場合は、ホワイトリストに"localhost"などを登録する必要があります。

ブラックリスト、ホワイトリストへの登録は、Web.configでも行えます。Web.configに記述した場合は、例えば以下のようになります(新たに追加が必要な個所のみを抜き出しています)。ここでは"localhost"と"127.0.0.1"をホワイトリストに入れ、ホスト名が"hogehoge.com"で終わるOPをブラックリストに入れています。

<configuration>
  <configSections>
    <sectionGroup name="dotNetOpenId">
      <section name="untrustedWebRequest"
               type="DotNetOpenId.Configuration.UntrustedWebRequestSection"
               requirePermission="false"
               allowLocation="false"/>
    </sectionGroup>
  </configSections>

  <dotNetOpenId>
     <untrustedWebRequest>
      <whitelistHosts>
        <add name="localhost" />
        <add name="127.0.0.1" />
      </whitelistHosts>
      <whitelistHostsRegex>
      </whitelistHostsRegex>
      <blacklistHosts>
      </blacklistHosts>
      <blacklistHostsRegex>
        <add name="(^|\.)hogehoge\.com$" />
      </blacklistHostsRegex>
    </untrustedWebRequest>
  </dotNetOpenId>
</configuration>

次回予告

次回はOpenIdLoginコントロールを使わずにRPを作る方法を紹介する予定です。

コメント

  • グッジョブ! -- K.Oumi 2009-07-07 (火) 09:17:16


ページ情報

*1 残念ながら、今のところ日本のOPでは積極的にお勧めできるところが見つかりませんが...。
*2 私の試した限りでは、この値を変更するとUriValidatorが無効になってしまうようだった。
[ トップ ]   [ 編集 | 凍結 | 差分 | バックアップ | 添付 | 複製 | 名前変更 | リロード ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]