「[[Open棟梁 wiki>https://opentouryo.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>汎用認証サイト(Multi-purpose Authentication Site)]] *目次 [#j24adbab] #contents *概要 [#i84718cb] [[汎用認証サイト(Multi-purpose Authentication Site)]]の独自仕様部分について説明する。 *Idp仕様 [#f550c2de] **概要 [#p07e3d3b] Idpの仕様については概ね、ASP.NET Identityに準拠。 ASP.NET Identity側の仕様については、「[[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]」を参照。 **カスタマイズ・ポイント [#n3b708da] ***マルチテナント化スイッチ [#j6087e30] ***RequireUniqueEmailスイッチ [#gbd5af06] -RequireUniqueEmail : true --UserName = E-mailアドレス --インターネット環境の標準の実装はこちら。 --E-mailアドレスでサインアップし、~ 直ちにE-mailアドレスの確認(E-mail confirmation)を行う。 -RequireUniqueEmail : false --UserName = 任意文字列 --ユーザストアを管理者が準備するエンプラ向き実装はこちら。 --E-mailアドレスの確認(E-mail confirmation)は不要 ---サインアップで、E-mailアドレスが提供されないので、~ E-mailアドレスの確認(E-mail confirmation)が実質的に不可能。 ---サインアップ画面を提供せず、管理者がアカウント(E-mailアドレス)を準備する。 ---若しくは、サインアップ画面を提供し、"ユーザ名 @ サイトのドメイン"でメアドを準備するなどとする。 --外部ログインの場合 ---サインアップ・サインインも可能ではある。 ---しかし、基本的には"外部ログイン = OFF"だと考える。 ***デバッグ用スイッチ [#s79a0f6c] -切替方法 --スイッチのON/OFF --ユーザストアへのアクセスにメモリ・プロバイダを指定している場合。 -動作 --デバッグ時:通知プロバイダを使用しない --本番時:通知プロバイダを使用する **利用するサービス [#a92c7f68] ***[[外部ログイン>#w534c815]] [#saead825] -Microsoft -Google -Facebook ***[[オンライン決済サービス>汎用認証サイト(Multi-purpose Authentication Site)#qf3fddd8]] [#mf9d3a00] -Stripe -PAY.JP ***[[通知プロバイダ>汎用認証サイト(Multi-purpose Authentication Site)#j3aea225]] [#i20fcfb1] -SMTP -SMS (Twilio) **ユーザ・アカウント [#xa20a1e2] ***主要属性 [#b725e4d1] -UserId = GUID -UserNameはスイッチ次第 --基本は、E-mailアドレス --スイッチ変更により、任意の文字列を使用可能。 -Passwordの強度は[[下記の設定>#x111a0c2]]に従う。 ***永続化 [#d378ad48] -[[EntityFramework>https://techinfoofmicrosofttech.osscons.jp/index.php?Entity%20Framework]]をキャンセルしUserStoreクラスで実装。 -DBMSはSQL Server or PostgreSQLを使用。 -Dapperを使用してデータアクセスを実装。 **スキーマ [#e472fd55] ***DDL [#ge5c13dd] Githubをポイント予定 ***編集処理 [#hfcc91ec] -管理画面でユーザ・ロールの属性値の編集が可能 -マルチテナント化している場合、テナント・データのみが対象になる。 -ユーザ管理 --管理者アカウントによるユーザ管理 --管理者アカウントとマルチテナント ---マルチテナントの場合:サインアップ・ユーザ ---マルチテナントでない場合:システム管理者 --編集可能な属性については[[こちら>#sc966644]]。 -ロール管理 --管理者アカウントによるユーザ管理 --管理者アカウントとマルチテナント ---マルチテナントの場合:サインアップ・ユーザ ---マルチテナントでない場合:システム管理者 **サインアップ・サインイン [#oe564461] ***サインアップとE-mailアドレス確認 [#rc86b3dc] -E-mailアドレスの確認(E-mail confirmation)は、~ 初回サインアップ後のレコードに対して行なう。 -E-mailアドレスの確認(E-mail confirmation)をしなかった場合、~ --サインアップをしようとすると、サインアップ済みの旨が表示される。 --E-mailアドレス確認は、初回サインアップ後のレコード(ユーザID・PWD)に対して行なう。 -初回サインアップ後、 --E-mailアドレス確認のメールをロストした場合、~ サインインを繰り返せば、再び、E-mailアドレス確認メールは飛ぶ。 --パスワードを失念した場合、[[パスワード・リセット>#f88a0fb5]]を行えばサインアップできる。 ***サインイン・サインアウト [#l4470148] 通常通り。 ***パスワード・リセット [#f88a0fb5] -パスワードを失念した場合 -サインアップ時のパスワードを失念した場合にも使用可能。 **アカウント編集 [#sc966644] ***パスワード [#u4227d89] -変更 -設定([[外部ログイン>#w534c815]]後、ローカル・ログオンを可能にする場合) ***[[外部ログイン>#w534c815]] [#z8a5ebd4] [[外部ログイン>#w534c815]]の一覧表示と追加・削除 ***電話番号 [#p3aec882] -編集(設定・削除)が可能 -[[通知プロバイダのSMS>汎用認証サイト(Multi-purpose Authentication Site)#j3aea225]]を使用。 ***[[二要素認証 (2FA) >#w7ba6fad]] [#b2ceb7bb] [[二要素認証 (2FA) >#w7ba6fad]]のON/OFF ***[[オンライン決済サービス>汎用認証サイト(Multi-purpose Authentication Site)#qf3fddd8]] [#hb5e1c33] クレジット・カードの登録 ***, etc. (任意項目を追加可能) [#z9bb4735] **二要素認証 [#w7ba6fad] ***有効化 [#q5586e1b] アカウント編集にて有効化 ***他のブラウザでテスト [#red3542c] -有効化した後は、他のブラウザでテストする。 -二要素認証はCookieを使用しているため、ブラウザ単位で行う。 **運用 [#q853018f] ***アカウント・ロックアウト [#tdca397b] 指定回数、ログインをミスすると、指定時間ロックアウトされる。 ***パスワード・リセット [#t06f7341] -通常のパスワード・リセットのシナリオ。 -例外的に以下のシナリオで使用する。 --初回サインアップ時のパスワードを失念した場合のシナリオ。 --[[外部ログイン>#w534c815]]後、ローカル・ログオンを可能にするシナリオ。 ***SecurityStamp [#vbd67fbf] -アカウント編集後にサインアウトされる。 -アカウント編集後にサインアウト・サインインする実装になっている理由はコレ。 *外部ログイン仕様 [#w534c815] **概要 [#x9ecc92c] 概ね、[[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]に準拠。 [[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]側の仕様については、「[[ASP.NET Identityの外部ログイン>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity%E3%81%AE%E5%A4%96%E9%83%A8%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3]]」を参照。 **カスタマイズ・ポイント [#n861c0bc] 外部ログイン処理の仕様について。 ***外部ログイン・サービス [#m1ac1110] -Microsoft -Google -Facebook -Twitter ***外部ログインでサインアップ [#cd8169dc] サインアップを外部ログインで行った場合、 -パスワードを持たないアカウントになる。 -この場合、後からパスワードを設定することで、ローカル・ログオンが可能になる。 --管理画面でパスワード追加する。 --パスワード・リセットを行なう。 -E-mailアドレスの確認(E-mail confirmation) --外部ログイン処理で取得したE-mailアドレスは確認しない。 --E-mailアドレスでサインアップして、そのままサインインする。 ***外部ログインでサインイン [#rcf9978e] -サインインのみ外部ログインで行った場合、 --既存のアカウントに認証連携でサインインできる。 --認証連携で必要なクレーム(属性値)を連携して上書きできる。 --UserNameやE-mailなど、変更できない属性値もある。 -外部ログイン追加、サインアップ、サインインの成・否は既定の動作のため省略。 ***外部ログインの一覧と削除 [#hbd8d5db] -サインアップ済みの状態から外部ログインの追加 → 削除~ 外部ログイン削除後のタイミングで、ログアウトしていないのは、~ 代替のログイン手段を持っているため問題無いということ。 -サインアップせずに、外部ログインの追加 → 削除~ --ローカル・ログオンを可能にしていない場合、最後の外部ログインを削除できなくなる。 --パスワード追加でローカル・ログオンを有効化すれば外部ログインを削除できる。 ***外部ログインの詳細 [#g27b9c4f] ExternalLoginCallbackの条件分岐 -AccountController --(1) 外部ログインの成否 ---失敗(異常終了) ---成功、(2) へ。 --(2) 外部ログインの有・無 ---既存の外部ログインがある → クレームを更新してサインイン(正常終了) ---既存の外部ログインがない →新規の外部ログインの追加、(3) へ。 --(3) 外部ログインの追加 ---当該ユーザが既にサインアップされている。~ → 外部ログイン、クレームを追加してサインイン(正常終了) ---当該ユーザが未だサインアップされていない。~ → サインアップ後に外部ログイン、クレームを追加してサインイン(正常終了) -ManageController --(1) 外部ログインの成否 ---失敗(異常終了) ---成功、(2) へ。 --(2) 外部ログインの有・無 ---既存の外部ログインがある → クレーム更新のみ行う(正常終了) ---既存の外部ログインがない →新規の外部ログインの追加、(3) へ。 --(3) 外部ログインの追加 ---当該ユーザが既にサインアップされている。~ → 外部ログイン、クレームを追加してサインイン(正常終了) ---当該ユーザが未だサインアップされていない。~ → このケースはありえない。 -クレームの連携(追加・更新)時に、ユーザ属性を更新するかどうか? --案件毎に決定してカスタマイズする。 --既定では、ユーザ属性の更新はしていない。 *[[OAuth>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth]] 2.0 Server仕様 [#td27d2c1] **概要 [#k234ea79] 概ね、[[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]に準拠。 -[[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]側の仕様 -[[OAuth>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth]]を拡張した認証の仕様 については、「[[ASP.NET IdentityによるSTS実装>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity%E3%81%AB%E3%82%88%E3%82%8BSTS%E5%AE%9F%E8%A3%85]]」を参照。 **共通 [#c15cd000] ***Server側 [#odd02418] -AuthorizationServer --認可エンドポイント ---redirect_uriチェックは不要(部分一致をサポートしない完全事前登録制とするため) --Tokenエンドポイント(Access Tokenの発行方法) ---scope=その他の値の場合、scopeパラメタ値をClaimに格納する(通常の動作)。 -ResourceServer --リソース・アクセス用のWeb APIを提供する。 ***Client側 [#y0f2a018] -パラメタ --redirect_uri指定は不要(部分一致をサポートしない完全事前登録制とするため) --state指定は必須(ID Tokenのnonce Claimにコレを設定する)。 -ResourceServerリソース・アクセス用のWeb APIにアクセスする場合、 --Access TokenをHTTPヘッダに指定して送信する。 ***Access Token [#d98eac8c] -Access Tokenのフォーマットには[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]アサーションを使用する。 --この[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]アサーションには、OpenID Connectと同様のID Tokenを含める。 --Access TokenはOAuthAuthorizationServerOptions.AccessTokenFormatに設定した、モジュールで生成される。 -AccessTokenFormatモジュールとの情報の受け渡しには、 --[[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]の仕組みに準拠し、ClaimsIdentityを使用する。 --ClaimsIdentityには、以下のようなURN形式の文字列をkeyに使用して、~ OAuthAuthorizationServer側からvalueの追加を行う(以下はscopeの値を設定する例)。 claimsIdentity.AddClaim(new Claim("urn:oauth:scope", xxxxx)); **クライアント認証 [#g7ed260c] ここでのクライアントとは、ユーザではなく、[[OAuth>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth]] 2.0 のClientを指しているので注意する。 -認可エンドポイントでは、クライアント認証ではなく、Redirectエンドポイントの検証を行う。 -クライアント認証は、Tokenエンドポイントにアクセスする際に行なう。 -ベーシック認証の認証ヘッダを使用して[[クライアント識別子>#hd5f827d]]を送信する。 ***クライアント識別子 [#hd5f827d] -GUIDを使用する --32文字の英数字。 --URLに指定するので、[{}, -] は無し。 -client_id~ 全てのグラント種別以外で必須 -client_secret --Implicitグラント種別以外で必須 --ただし、[[ユーザ認証>#k61b5f5a]]で使用する場合は、Implicitグラント種別でも必須。 **ユーザ認証 [#k61b5f5a] ***Server側 [#jdc096e3] -Access TokenにOpenID Connectと同様のID Token([[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]アサーション)を含める。 -ApplicationOAuthBearerTokenProviderの実装 --ValidateClientRedirectUriのオーバーライド --- --xxxxx ---xxxxxxxxxx -[[クライアント識別子>#hd5f827d]]は全てのグラント種別で必須となる。 ***Client側 [#hc71d0be] -グラント種別 --できるだけ、Authorization Codeグラント種別を使用する。 --Implicitグラント種別もサポートするが、その場合、~ [[ユーザ認証>#k61b5f5a]]用Access Tokenと[[クライアント識別子>#hd5f827d]]の露見のリスクがあることに注意すること。 --従って、できるだけ、[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]アサーションをClient側で検証することが推奨される。 -パラメタ --response_typeには、"code"(推奨) or "token"を指定する。 -ResourceServerの[[ユーザ認証>#k61b5f5a]]専用のWebAPIにアクセスする場合、 --[[ユーザ認証>#k61b5f5a]]用Access Tokenに加え、前述の[[クライアント識別子>#hd5f827d]]をPOSTで送信する。 ***ResourceServerのWebAPI [#f23f0dde] -/api/OAuthResourceApi/GetUserClaim *パラメタ化 [#fe16f728] **Idp [#c4df20df] [[ASP.NET Identity>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Identity]]や、その他、アプリケーションで使用するパラメタについて。 ***SecurityStamp [#u19d11f5] <!-- SecurityStamp(検証間隔は10秒、本番は長めに設定--> <add key="SecurityStampValidateIntervalFromSeconds" value="10" /> ***ユーザ名と、その検証 [#vf58cd02] -ユーザ名は、E-mailアドレスとする。 -サインアップ後にE-mailアドレスの確認(E-mail confirmation)をする。 <!--ユーザ名検証(ユーザ名は、E-mail--> <add key="AllowOnlyAlphanumericUserNames" value="false" /> <add key="RequireUniqueEmail" value="true" /> ***パスワード検証 [#x111a0c2] <!--パスワード検証(8文字以上の大文字・小文字、数値、記号--> <add key="RequiredLength" value="8" /> <add key="RequireNonLetterOrDigit" value="true" /> <add key="RequireDigit" value="true" /> <add key="RequireLowercase" value="true" /> <add key="RequireUppercase" value="true" /> ***ユーザ ロックアウト [#d59dc445] <!--ユーザ ロックアウト(5 回入力ミスすると、5分ロックアウト--> <add key="UserLockoutEnabledByDefault" value="true" /> <add key="DefaultAccountLockoutTimeSpanFromSeconds" value="300" /> <add key="MaxFailedAccessAttemptsBeforeLockout" value="5" /> ***二要素認証 [#o4aac430] <!-- 二要素認証(2FA:TwoFactorAuthentication)--> <!-- 必要に応じてユーザが有効にするので初期値は false --> <add key="TwoFactorEnabled" value="false" /> <!-- Cookieの有効期限は二週間 24 * 14 = 336 時間 --> <add key="TwoFactorCookieExpiresFromHours" value="336" /> **外部ログイン [#ud14e362] 以下のように各、外部ログイン・プロバイダの -有効化・無効化 -クライアント認証のための[[クライアント識別子>#hd5f827d]] を設定できる。 <!-- 外部ログインの追加時に XSRF の防止 --> <add key="XsrfKey" value="(サイト毎にで変更する、公開しないこと)" /> <!--外部ログイン(MicrosoftAccountAuthentication)--> <add key="MicrosoftAccountAuthentication" value="true" /> <add key="MicrosoftAccountAuthenticationClientId" value="・・・" /> <add key="MicrosoftAccountAuthenticationClientSecret" value="・・・" /> <!--外部ログイン(GoogleAuthentication)--> <add key="GoogleAuthentication" value="true" /> <add key="GoogleAuthenticationClientId" value="・・・" /> <add key="GoogleAuthenticationClientSecret" value="・・・" /> <!--外部ログイン(FacebookAuthentication)--> <add key="FacebookAuthentication" value="true" /> <add key="FacebookAuthenticationClientId" value="・・・" /> <add key="FacebookAuthenticationClientSecret" value="・・・" /> ***設定値の取得方法など [#te545c64] [[クライアント識別子>#hd5f827d]]は、外部ログイン・サービスの管理画面から取得する。 合わせてここでRedirectエンドポイントの設定などを行う必要がある。~ これは、外部ログイン・サービス毎に設定方法が異なるので注意する。 例えばマイクロソフト・アカウントでは、以下の様な設定を行う。、 https://fqdnname:nnnnn/signin-microsoft 外部ログイン・サービスによっては、httpやlocalhostをサポートしないことがある。 ***XsrfKey [#va1455fb] -asp.net mvc 5 - What is the XsrfKey used for and should I set the XsrfId to something else? - Stack Overflow~ http://stackoverflow.com/questions/32121504/what-is-the-xsrfkey-used-for-and-should-i-set-the-xsrfid-to-something-else XsrfKeyは、XSRF = CSRFを防ぐためのstateパラメタの生成に使用される。~ stateパラメタは暗号化によって生成されるので、XsrfKey自体が露見することはない。~ 従って、この値としても、無作為な値を使用する必要はない。 **OAuth 2.0 Server [#kf7a470c] ***共通設定 [#ie197aca] -[[OAuth>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth]] 2.0 STSの有効化・無効化設定 <!-- 共通設定 --> <add key="EquipOAuthServer" value="true" /> -OAuthAuthorizationServerOptions <!-- プロパティ --> <add key="AllowOAuthInsecureHttpEndpoints" value="true" /> <add key="OAuthAuthorizeEndpointCanDisplayErrors" value="true" /> <add key="OAuthAccessTokenExpireTimeSpanFromMinutes" value="360" /> <add key="OAuthRefreshTokenExpireTimeSpanFromDays" value="14" /> -[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]アサーション関連の設定 <!-- JWT --> <add key="OAuthIssuerId" value="http://jwtssoauth.opentouryo.com" /> <!-- JWTの署名に使用する X.509 証明書に関するパラメタ --> <add key="OAuthJWTPassword" value="xxxxx" /> <add key="OAuthJWT_pfx" value="XXXXX_RS256.pfx" /> <add key="OAuthJWT_cer" value="XXXXX_RS256.cer" /> -Grant Typeの有効・無効 <!-- Grant Typeの有効・無効 --> <add key="EnableResourceOwnerCredentialsGrantType" value="true" /> <add key="EnableClientCredentialsGrantType" value="true" /> <add key="EnableRefreshToken" value="true" /> ***Server側エンドポイント [#e48bbad2] -Authorization Serverエンドポイント <!-- AuthorizationServerエンドポイント --> <add key="OAuthAuthorizationServerEndpointsRootURI" value="http://localhost:nnnnn/MultiPurposeAuthSite" /> <!-- 認可エンドポイント --> <add key="OAuthAuthorizeEndpoint" value="/Account/OAuthAuthorize" /> <!-- Tokenエンドポイント --> <add key="OAuthBearerTokenEndpoint" value="/OAuthBearerToken" /> -Resource Serverエンドポイント <!-- ResourceServerエンドポイント --> <add key="OAuthResourceServerEndpointsRootURI" value="http://localhost:nnnnn/MultiPurposeAuthSite" /> <add key="OAuthAuthenticateUserWebAPI" value="/api/OAuthResourceApi/AuthenticateUser" /> <add key="OAuthGetUserClaimWebAPI" value="/api/OAuthResourceApi/GetUserClaim" /> ***Client側エンドポイント [#c862d00c] <!-- Client --> <!-- Clientエンドポイント --> <add key="OAuthClientEndpointsRootURI" value="http://localhost:nnnnn/MultiPurposeAuthSite" /> <!-- Redirectエンドポイント --> <!-- - test_self_code : Authorization Codeグラント種別 --> <add key="OAuthAuthorizationCodeGrantClient" value="/Account/OAuthAuthorizationCodeGrantClient" /> <!-- - test_self_token : Implicitグラント種別 --> <add key="OAuthImplicitGrantClient" value="/Account/OAuthImplicitGrantClient" /> ***[[クライアント識別子>#hd5f827d]] [#mc385a2d] 以下をツールを使用して生成して、登録する。 -先頭の[[クライアント識別子>#hd5f827d]]は、テスト用Redirectエンドポイントを使用するテスト用。 -以降の[[クライアント識別子>#hd5f827d]]は、ユーザのサイト。 <!-- クライアント識別子 (client_id, client_secret, redirect_uri) --> <add key="OAuthClientsInformation" value=' { "-guid(client_id)-": { "client_secret": "-乱数-", "redirect_uri_code": "test_self_code", "redirect_uri_token": "test_self_token", "client_name": "TestUser" }, "-guid(client_id)-": { "client_secret": "-乱数-", "redirect_uri_code": "http://hogehoge0/aaa", "redirect_uri_token": "http://hogehoge0/bbb", "client_name": "hogehoge0" }, "-guid(client_id)-": { "client_secret": "-乱数-", "redirect_uri_code": "http://hogehoge1/aaa", "redirect_uri_token": "http://hogehoge1/bbb", "client_name": "hogehoge1" }, "-guid(client_id)-": { "client_secret": "-乱数-", "redirect_uri_code": "http://hogehoge2/aaa", "redirect_uri_token": "http://hogehoge2/bbb", "client_name": "hogehoge2"