「[[Open棟梁 wiki>https://opentouryo.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>汎用認証サイトのファーストステップガイド]]
--[[汎用認証サイトのファーストステップガイド (1)]]
--[[汎用認証サイトのファーストステップガイド (2)]]
--[[汎用認証サイトのファーストステップガイド (3)]]
--汎用認証サイトのファーストステップガイド (4)
--[[汎用認証サイトのファーストステップガイド (5)]]
--[[ファーストステップ (1)>汎用認証サイトのファーストステップガイド (1)]]
--[[ファーストステップ (2)>汎用認証サイトのファーストステップガイド (2)]]
--[[ファーストステップ (3)>汎用認証サイトのファーストステップガイド (3)]]
--ファーストステップ (4)
--[[ファーストステップ (5)>汎用認証サイトのファーストステップガイド (5)]]
--[[ファーストステップ (6)>汎用認証サイトのファーストステップガイド (6)]]
--[[ファーストステップ (7)>汎用認証サイトのファーストステップガイド (7)]]

*目次 [#hddf7023]
#contents

*概要 [#lbdaf1e3]
[[汎用認証サイト(Multi-purpose Authentication Site)]]~
の導入前の評価を行うためのファーストステップガイド。

(4) では、「認証連携コードの実装」を行う。

*サンプル・プロジェクト [#nadadb6c]
ココで実装するコードは、

下記に添付した、

-ASP.NET MVC版サンプル~
&ref(WebApplication1.zip);

-同様に作成した、ASP.NET WebForms版サンプル~
&ref(WebApplication2.zip);

-同様に作成した、[[SpringMVC(Java)版サンプル>#i5d3d94b]]~

からダウンロード可能です。

*汎用認証サイトをセットアップする。 [#m6718c37]
-適当なところに汎用認証サイトをセットアップする。
-[[3 分割テスト>汎用認証サイトのファーストステップガイド (3)#r68f6218]]で行ったように、ポート番号が違うならlocalhostでも良い。
-ここでは、別サーバーのIIS上にデプロイ、セットアップしたので汎用認証サイトは常に実行可能状態にある。
-ローカル開発環境でテストする場合は、必要に応じて、汎用認証サイトをデバッグ起動して実行可能状態にする。

*クライアントのプロジェクトを作成する。 [#l8d51863]
ここでは、クライアントのプロジェクトとして、ASP.NET MVCを選択する。

**ASP.NET MVCのプロジェクトを新規作成する。 [#v7dfdc59]
ASP.NET MVCの(ASP.NET Web Application)プロジェクトを新規作成する。

[メニュー] ---> [新規作成] --->
>[プロジェクト] ---> [ASP.NET Web Application(.NET Framework)]

***新しいプロジェクト [#le7af872]
-任意のパスを指定

-名前を入力
--例えば[WebApplication1]という既定の名称を使用する。
--ソリューション名も同じ名称のままにする。

-[OK]ボタンを押下。

***テンプレート選択 [#s719107d]
テンプレート選択画面で以下のように選択する。

-テンプレートとして、[MVC]を選択する。
-[認証の変更ボタン]を押下し、[認証なし]に変更する。
-[OK]ボタンを押下してプロジェクトを作成する。
-※ [クラウドにホストする]チェック ボックスのチェックは外す。

**余分なコードを削除する。 [#tbfa323e]
***Controller [#k9aeec88]
HomeControllerから以下のアクション・メソッドを削除
-About
-Contact

***View [#rc37b85d]

-[[上記のアクション・メソッド>#k9aeec88]]に対応するViewも削除する。
--~/Home/About.cshtml
--~/Home/Contact.cshtml

-_Layout.cshtml

--以下のdivは不要なので消す。
 <div class="navbar navbar-inverse navbar-fixed-top">

--以下を以下で置き換える。
---以下のdivを
 <div class="container body-content">
---以下のステートメントで置き換える。
 @RenderBody()

--以下のような状態になる。
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
     <meta charset="utf-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>@ViewBag.Title - マイ ASP.NET アプリケーション</title>
     @Styles.Render("~/Content/css")
     @Scripts.Render("~/bundles/modernizr")
 </head>
 <body>
     @RenderBody()
 
     @Scripts.Render("~/bundles/jquery")
     @Scripts.Render("~/bundles/bootstrap")
     @RenderSection("scripts", required: false)
 </body>
 </html>

-~/Home/Index.cshtml

--以下を残して全て消す。
 @{
     ViewBag.Title = "Home Page";
 }

*クライアントにRedirectエンドポイントを作成する。 [#we465a2c]
**サンプルコードをコピーする。 [#j5235722]
[[汎用認証サイトのAccountController>https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Controllers/AccountController.cs#L1258]]からサンプルのRedirectエンドポイントである~
AccountController.OAuthAuthorizationCodeGrantClientアクション・メソッドをコピーする。
[[汎用認証サイトのAccountController>https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Controllers/AccountController.cs]]からサンプルのRedirectエンドポイントである

***Authorization Codeグラント種別 [#f687dd62]
[[AccountController.OAuthAuthorizationCodeGrantClientアクション・メソッド>https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Controllers/AccountController.cs#L1669]]をコピーする。

***Implicitグラント種別 [#a9669a55]
[[AccountController.OAuthImplicitGrantClientアクション・メソッド>https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Controllers/AccountController.cs#L1848]]をコピーする。

**サンプルコードを貼り付ける。 [#u2eec88f]
***Authorization Codeグラント種別 [#eae7d995]
-HomeControllerにコピーしたOAuthAuthorizationCodeGrantClientアクション・メソッドを貼り付ける。

-最初のうちは、ほぼほぼコンパイル エラーになるので、以下のようにコメント アウトし、

-最後に、「return View("");」を加えておく。
-最後に、「return View("");」を加えて、
 [HttpGet]
 [AllowAnonymous]
 public async Task<ActionResult> OAuthAuthorizationCodeGrantClient(string code, string state)
 {
     // ・・・コメントアウト・・・
     
     return View("");
 }

-Viewモジュールを~/Home/OAuthAuthorizationCodeGrantClient.cshtmlという名称で作成しておく。

***Implicitグラント種別 [#z4b87f68]
-HomeControllerにコピーしたOAuthImplicitGrantClientアクション・メソッドを貼り付ける。

-最初のうちは、ほぼほぼコンパイル エラーになるので、以下のようにコメント アウトし、

-最後に、「return View("");」を加えて、
 [HttpGet]
 [AllowAnonymous]
 public async Task<ActionResult> OAuthImplicitGrantClient(string code, string state)
 {
     // ・・・コメントアウト・・・
     
     return View("");
 }

-Viewモジュールを~/Home/OAuthImplicitGrantClient.cshtmlという名称で作成しておく。

*汎用認証サイトにRedirectエンドポイントのURLを設定する。 [#dba08db1]
-以下のclient_id部分に、以下のように、Redirectエンドポイントを設定する。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/app.config#L227
 "f53469c17c5a432f86ce563b7805ab89": {
 "client_secret": "cKdwJb6mRKVIJpGxEWjIC94zquQltw_ECfO-55p21YM",
 "redirect_uri_code": "http://(クライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient",
 "redirect_uri_token": "http://hogehoge0/bbb",
 "client_name": "test_icon"
-[[以下のclient_id部分に、以下のように、Redirectエンドポイントを設定する>汎用認証サイトのコンフィギュレーション#v637e44e]]。
 "21c7769f16634dabaf14282602b9a5fc": {
   "client_secret": "xrRczIidMMZcMxvYWpIkvSZX1oRj2CLzVFSOkl7ocLY",
   "redirect_uri_code": "http://(MVCクライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient",
   "redirect_uri_token": "http://(MVCクライアント・サイトのアドレス:ポート)/Home/OAuthImplicitGrantClient",
   "client_name": "WebApplication1(MVC)"
 },
 "a0d280a6da034eb8ba821a651da829fc": {
   "client_secret": "eufLXjWaaQgiBXiiGZ-36N-bb4hOHy8H1TIEk126QDg",
   "redirect_uri_code": "http://(WebFormクライアント・サイトのアドレス:ポート)/OAuthAuthorizationCodeGrantClient.aspx",
   "redirect_uri_token": "http://(WebFormクライアント・サイトのアドレス:ポート)/OAuthImplicitGrantClient.aspx",
   "client_name": "WebApplication2(WebForms)"
 },

-なお、このセクションは「CreateClientsIdentity.exe」使用して自動生成できる。

*クライアントにスターターのリンクを設置する。 [#q8d7b767]
*認可リクエスト・認可レスポンス [#x3db3b0f]
**クライアントにスターター(認可リクエスト)のリンクを設置する。 [#q8d7b767]

**スターターのリンクを取得 [#jd4f0e5f]
***スターターのリンクを取得 [#jd4f0e5f]
-スターターは汎用認証サイトを実行したトップ画面画から取得する。
--Authorization Codeグラント種別
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=67d328bfe8604aae83fb15fa44780d8b&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L

--Implicitグラント種別
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=67d328bfe8604aae83fb15fa44780d8b&response_type=token&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L

#ref(0.png,left,nowrap,0)

**スターターのリンクを設置 [#fe72f177]
***スターターのリンクを設置 [#fe72f177]
-スターターの「ホスト:ポート」部分を書き換えてIndex.cshtmlに貼り付ける。
 <a href="http://(クライアント・サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=67d328bfe8604aae83fb15fa44780d8b&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始</a>
--Authorization Codeグラント種別
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=21c7769f16634dabaf14282602b9a5fc&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L

-次に、client_idを書き換える。具体的には、「67d328bfe8604aae83fb15fa44780d8b」から「f53469c17c5a432f86ce563b7805ab89」に書き換える。
 <a href="http://(クライアント・サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=f53469c17c5a432f86ce563b7805ab89&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始</a>
--Implicitグラント種別
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=21c7769f16634dabaf14282602b9a5fc&response_type=token&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L

*クライアントをデバッグ実行し、仲介コードを確認する。 [#p1b6df91]
**ブレークポイントを仕掛ける。 [#x5c3dcc8]
-次に、client_idを書き換える。
--具体的には、「67d328bfe8604aae83fb15fa44780d8b」から
---MVC「21c7769f16634dabaf14282602b9a5fc」に書き換える。
---Web Forms「a0d280a6da034eb8ba821a651da829fc」に書き換える。

--Authorization Codeグラント種別
---MVC
 <a href="http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=21c7769f16634dabaf14282602b9a5fc&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始(code)</a><br/>
---Web Forms
 <a href="http://localhost:63359/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=a0d280a6da034eb8ba821a651da829fc&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始(code)</a><br/>

--Implicitグラント種別
---MVC
 <a href="http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=21c7769f16634dabaf14282602b9a5fc&response_type=token&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始(token)</a><br />
---Web Forms
 <a href="http://localhost:63359/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=a0d280a6da034eb8ba821a651da829fc&response_type=token&scope=profile%20email%20phone%20address%20userid%20aaa%20bbb&state=vj9NCxij4L">開始(token)</a><br />

-ポイント:~
サーバーに指定したRedirectエンドポイントを使用するため、~
ここでは、認可リクエストにredirect_uriパラメタを追加しない。

**クライアントをデバッグ実行し、認可レスポンスを確認する。 [#p1b6df91]

***Authorization Codeグラント種別 [#hfcbba9f]
-ブレークポイントを仕掛ける。~
RedirectエンドポイントであるOAuthAuthorizationCodeGrantClientアクション・メソッドにブレークポイントを仕掛ける。

**クライアントをデバッグ実行してスターターをクリック [#q259f27b]
-クライアントをデバッグ実行してAuthorization Codeグラント種別のスターターをクリック~
この状態でクライアント・サイトをデバッグ実行して、スターターをクリックしてみる。

**プレークポイントにブレーク(中断)するのを確認する。 [#rc13061b]
-プレークポイントにブレーク(中断)するのを確認する。~

-汎用認証サイトの認証、(認可エンドポイントでの)認可プロセスを経て、
--汎用認証サイトの認証、(認可エンドポイントでの)認可プロセスを経て、

-クライアント・サイトのRedirectエンドポイントである~
--クライアント・サイトのRedirectエンドポイントである~
OAuthAuthorizationCodeGrantClientアクション・メソッドでブレーク(中断)するのを確認する。

-ここで、以下のように、仲介コードを確認することができる。~
以降コレを、AccessTokenとRefreshTokenに変換する。
--ここで、以下のように、仲介コードを確認することができる。~
以降コレ(仲介コード)を、アクセストークンとリフレッシュトークンに変換する処理を実装する。
>
#ref(1.png,left,nowrap,1)

*仲介コードをAccessTokenとRefreshTokenに変換する。 [#b04f025b]
***Implicitグラント種別 [#a746d77f]
-ブレークポイントを仕掛ける。~
RedirectエンドポイントであるOAuthImplicitGrantClientアクション・メソッドにブレークポイントを仕掛ける。

-クライアントをデバッグ実行してImplicitグラント種別のスターターをクリック~
この状態でクライアント・サイトをデバッグ実行して、スターターをクリックしてみる。

-プレークポイントにブレーク(中断)するのを確認する。~

--汎用認証サイトの認証、(認可エンドポイントでの)認可プロセスを経て、

--クライアント・サイトのRedirectエンドポイントである~
OAuthImplicitGrantClientアクション・メソッドでブレーク(中断)するのを確認する。

--Implicitグラント種別では、「URLフラグメント」を使用して情報を受け渡すため、~
サーバー側では、何も確認できないので、F5押下で画面表示し、URLからアクセストークンを確認する。
>
#ref(1a.png,left,nowrap,1a,80%)

*アクセストークン・リクエスト、レスポンス(Authorization Codeのみ) [#m5b26214]
-アクセストークン・リクエスト
-アクセストークン・レスポンス~

によって、仲介コードを

-アクセストークンと
-リフレッシュトークンに

変換する。

なお、この処理は、Authorization Codeでのみ必要になる。

**必要な情報の収集 [#q97ffaa9]
以下を必要とする。

***アクセストークン・リクエストの仕方。 [#k1d931a7]
-アクセストークン・リクエストについては、[[こちら>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth#yfeb403d]]を参照。
-アクセストークン・リクエストについては、[[コチラ>https://techinfoofmicrosofttech.osscons.jp/index.php?OAuth#yfeb403d]]を参照。

-ザックリと、以下のようなリクエストを送信する。
 POST /token HTTP/1.1
  Host: server.example.com
  Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
  Content-Type: application/x-www-form-urlencoded
 
  grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
  &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

-ここでは、以下のようになる。
 POST /MultiPurposeAuthSite/OAuthBearerToken
 HTTP/1.1
  Host: (汎用認証サイトのアドレス:ポート)
  Authorization: Basic ["client_Id:client_secret"をbase64 url encodeした値]
  Content-Type: application/x-www-form-urlencoded
 
  grant_type=authorization_code&code=[取得した仲介コードの値]

***TokenエンドポイントのURL [#vaa26fc4]
-Tokenエンドポイントは、以下に設定されている。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/app.config#L199

-汎用認証サイトのURLと繋げて、以下のようになる。
-[[app.configにTokenエンドポイントのパスが設定されている。>汎用認証サイトのコンフィギュレーション#se5f4174]]
-汎用認証サイト(AuthorizationServerエンドポイント)のURLと繋げて、以下のようになる。
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/OAuthBearerToken

***client_Idとclient_secret [#qc267a07]
-client_Idとclient_secretは以下に設定されている。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/app.config#L227
-[[app.configにclient_Idとclient_secretが設定されている。>汎用認証サイトのコンフィギュレーション#v637e44e]]

-client_Idとclient_secretの値はそれぞれ、~
--client_Id : f53469c17c5a432f86ce563b7805ab89
--client_secret : cKdwJb6mRKVIJpGxEWjIC94zquQltw_ECfO-55p21YM
-ここでは、client_Idとclient_secretの値として、それぞれ、~
--client_Id : 21c7769f16634dabaf14282602b9a5fc
--client_secret : xrRczIidMMZcMxvYWpIkvSZX1oRj2CLzVFSOkl7ocLY

>を利用する。

***RedirectエンドポイントのURL [#vaa26fc4]
-[[Redirectエンドポイントは前述の値>#dba08db1]]。

-ここでは、以下のようになる。
 http://(クライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient

**[[HttpClient>https://techinfoofmicrosofttech.osscons.jp/index.php?HttpClient%E3%81%AE%E9%A1%9E%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9]]を使用してアクセストークン・リクエストを行う。 [#b8eff20c]
**[[HttpClient>https://techinfoofmicrosofttech.osscons.jp/index.php?HttpClient%E3%81%AE%E9%A1%9E%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9]]を使用して仲介コードをアクセストークンとリフレッシュトークンに変換する。 [#b8eff20c]

***コード [#l1699430]
だいたい、以下のような感じのコードになる。

 using System;
 using System.Text;
 using System.Collections.Generic;
 using System.Web.Mvc;
 using System.Net.Http;
 using System.Net.Http.Headers;
 using System.Threading.Tasks;
 
 using Microsoft.Owin.Security.DataHandler.Encoder;
 
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
 namespace WebApplication1.Controllers
 {
     public class HomeController : Controller
     {
         public ActionResult Index()
         {
             return View();
         }
 
         [HttpGet]
         [AllowAnonymous]
         public async Task<ActionResult> OAuthAuthorizationCodeGrantClient(string code, string state)
         {
             if (state == "vj9NCxij4L") // CSRF(XSRF)対策のstateの検証は重要
             {
                 HttpClient httpClient = new HttpClient();
 
                 HttpRequestMessage httpRequestMessage = null;
                 HttpResponseMessage httpResponseMessage = null;
 
                 // HttpRequestMessage (Method & RequestUri)
                 HttpRequestMessage httpRequestMessage = new HttpRequestMessage
                 httpRequestMessage = new HttpRequestMessage
                 {
                     Method = HttpMethod.Post,
                     RequestUri = new Uri("http://10.231.20.145/MultiPurposeAuthSite/OAuthBearerToken"),
                     RequestUri = new Uri("http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/OAuthBearerToken"),
                 };
 
                 // HttpRequestMessage (Headers & Content)
                 httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
                     "Basic",
                     Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(
                         string.Format("{0}:{1}",
                             "f53469c17c5a432f86ce563b7805ab89",
                             "cKdwJb6mRKVIJpGxEWjIC94zquQltw_ECfO-55p21YM"))));
                             "21c7769f16634dabaf14282602b9a5fc",
                             "xrRczIidMMZcMxvYWpIkvSZX1oRj2CLzVFSOkl7ocLY"))));
 
                 httpRequestMessage.Content = new FormUrlEncodedContent(
                     new Dictionary<string, string>
                     {
                         { "grant_type", "authorization_code" },
                         { "code", code },
                         { "redirect_uri", System.Web.HttpUtility.HtmlEncode("http://localhost:62517/Home/OAuthAuthorizationCodeGrantClient") },
                         { "redirect_uri", System.Web.HttpUtility.HtmlEncode("http://(クライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient") },
                     });
 
                 // HttpResponseMessage
                 HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
                 httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
                 string response = await httpResponseMessage.Content.ReadAsStringAsync();
 
                 // 汎用認証サイトのOAuth2.0のレスポンスに含まれるaccess_tokenは、id_tokenのようなformatをしている。ここからsubを取得可能。
                 Base64UrlTextEncoder base64UrlEncoder = new Base64UrlTextEncoder();
                 Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
                 JObject jobj = ((JObject)JsonConvert.DeserializeObject(Encoding.UTF8.GetString(base64UrlEncoder.Decode(dic["access_token"].Split('.')[1]))));
                 string jwtPayload = Encoding.UTF8.GetString(base64UrlEncoder.Decode(dic["access_token"].Split('.')[1]));
 
                 // id_tokenライクなJWTなので、中からsubなどを取り出すことができる。
                 JObject jobj = ((JObject)JsonConvert.DeserializeObject(jwtPayload));
                 string sub = (string)jobj["sub"];
             }
 
             return View("");
         }
 
     }
 }

***実行結果 [#i62ef920]
-subが取得できれば、アクセストークンの取得に成功している。
-必要に応じて、JWTの署名検証、内容検証を行えば、より確実と言える。
上記の、「dic["access_token"]」の部分が、アクセストークンである。

汎用認証サイトでは、[[設定によって>汎用認証サイトのコンフィギュレーション#k8279ce6]]アクセストークンのformatを、ASP.NET Identity形式と[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]形式から選択できる。

#ref(2.png,left,nowrap,2)

***署名検証、内容検証 [#va8ac3c1]
アクセストークンのformatgが、[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]形式の場合、~
必要に応じて、[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]の署名検証、内容検証を行えば、セキュリティ的に、より確実と言える。

-署名検証
--汎用認証サイトから公開鍵を入手する。
--Open棟梁では、JWTの署名検証ライブラリを提供している。
--JWTの署名検証ライブラリの使用方法については以下が参考になる。~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Models/ASPNETIdentity/TokenProviders/AccessTokenFormatJwt.cs#L191

-内容検証~
まず、"sub"が取得できれば、アクセストークンの取得に成功していると言える。~
そして、最低限、"iss"・"aud"、"nonce"クレームの内容検証を行うと良い。
---"iss"クレームには、当該トークンを発行したSTSを表すUri値が格納される。
---"aud"クレームには、起動パラメタの"client_id"値が格納される。
---"nonce"クレームには、起動パラメタの"state"値が格納される。

-この[[JWT>https://techinfoofmicrosofttech.osscons.jp/index.php?JWT]]の署名検証、内容検証には「https://jwt.io/」を使用できる。
--詳しくは[[コチラ>汎用認証サイトのファーストステップガイド (1)#b6c3cd0c]]を参照。

*アクセストークンを使用しResource ServerのWebAPIへのアクセス結果を出力する。 [#u9bd4699]

**Authorization Codeグラント種別 [#ka9fbeb3]

***必要な情報の収集 [#sb982345]
-/userinfoエンドポイントのURL
--[[app.configに/userinfoエンドポイントのパスが設定されている。>汎用認証サイトのコンフィギュレーション#se5f4174]]

--汎用認証サイト(Resource Serverエンドポイント)のURLと繋げて、以下のようになる。
 http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/userinfo

***/userinfoエンドポイントにアクセスして、ユーザ属性を取得する。 [#df413385]

-コード~
[[先程のコード>#l1699430]]に追記を行い、以下のような感じにする。
 using System;
 using System.Text;
 using System.Collections.Generic;
 using System.Web.Mvc;
 using System.Net.Http;
 using System.Net.Http.Headers;
 using System.Threading.Tasks;
 
 using Microsoft.Owin.Security.DataHandler.Encoder;
 
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
 namespace WebApplication1.Controllers
 {
     public class HomeController : Controller
     {
         public ActionResult Index()
         {
             return View();
         }
 
         [HttpGet]
         [AllowAnonymous]
         public async Task<ActionResult> OAuthAuthorizationCodeGrantClient(string code, string state)
         {
             if (state == "vj9NCxij4L") // CSRF(XSRF)対策のstateの検証は重要
             {
                 HttpClient httpClient = new HttpClient();
 
                 HttpRequestMessage httpRequestMessage = null;
                 HttpResponseMessage httpResponseMessage = null;
 
                 // HttpRequestMessage (Method & RequestUri)
                 httpRequestMessage = new HttpRequestMessage
                 {
                     Method = HttpMethod.Post,
                     RequestUri = new Uri("http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/OAuthBearerToken"),
                 };
 
                 // HttpRequestMessage (Headers & Content)
                 httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
                     "Basic",
                     Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(
                         string.Format("{0}:{1}",
                             "21c7769f16634dabaf14282602b9a5fc",
                             "xrRczIidMMZcMxvYWpIkvSZX1oRj2CLzVFSOkl7ocLY"))));
 
                 httpRequestMessage.Content = new FormUrlEncodedContent(
                     new Dictionary<string, string>
                     {
                         { "grant_type", "authorization_code" },
                         { "code", code },
                         { "redirect_uri", System.Web.HttpUtility.HtmlEncode("http://(クライアント・サイトのアドレス:ポート)/Home/OAuthAuthorizationCodeGrantClient") },
                     });
 
                 // HttpResponseMessage
                 httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
                 string response = await httpResponseMessage.Content.ReadAsStringAsync();
 
                 // 汎用認証サイトのOAuth2.0のレスポンスに含まれるaccess_tokenは、id_tokenのようなformatをしている。ここからsubを取得可能。
                 Base64UrlTextEncoder base64UrlEncoder = new Base64UrlTextEncoder();
                 Dictionary<string, string> dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
                 string jwtPayload = Encoding.UTF8.GetString(base64UrlEncoder.Decode(dic["access_token"].Split('.')[1]));
 
                 // id_tokenライクなJWTなので、中からsubなどを取り出すことができる。
                 JObject jobj = ((JObject)JsonConvert.DeserializeObject(jwtPayload));
                 string sub = (string)jobj["sub"];

>↓↓↓ 下を追加 ↓↓↓
                 // Userエンドポイントに問い合わせを行う。
                 
                 // HttpRequestMessage (Method & RequestUri)
                 httpRequestMessage = new HttpRequestMessage
                 {
                     Method = HttpMethod.Get,
                     RequestUri = new Uri("http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/userinfo"),
                 };
 
                 // HttpRequestMessage (Headers)
                 httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", dic["access_token"]);
 
                 // HttpResponseMessage
                 httpResponseMessage = await httpClient.SendAsync(httpRequestMessage);
                 string userinfo = await httpResponseMessage.Content.ReadAsStringAsync();
                 jobj = ((JObject)JsonConvert.DeserializeObject(userinfo));
                 sub = (string)jobj["sub"];
             }
 
             // 基本的に、仲介コードやアクセストークンは画面に露見させないこと。
             // このまま画面に表示させるとQuerystringに仲介コードが露見するので、
             // 必要な情報位を取得した後に、一段、Redirect処理などを経由させると良い。

>↑↑↑ 上を追加 ↑↑↑
             return View("");
         }
 
     }
 }

-実行結果
>
#ref(3.png,left,nowrap,3)

***注意事項 [#z796a2ba]
-仲介コードやアクセストークンは画面に露見させないこと。

-このまま画面に表示させるとQuerystringに仲介コードが露見するので、~
必要な情報位を取得した後に、一段、Redirect処理などを経由させると良い。

**Implicitグラント種別 [#b7c19466]
前述の[[Authorization Codeグラント種別>#ka9fbeb3]]と異なり、~
この後の処理をクライアントサイドのJavaScriptで行う。

***必要な情報の収集 [#ydacf245]
[[前述>#sb982345]]と同じ。

***/userinfoエンドポイントにアクセスして、ユーザ属性を取得する。 [#sfef139a]
以下のモジュールから、

-OAuthImplicitGrantClient.cshtml~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Views/Account/OAuthImplicitGrantClient.cshtml
-oauthimplicit.js~
https://github.com/OpenTouryoProject/MultiPurposeAuthSite/blob/develop/root/programs/MultiPurposeAuthSite/MultiPurposeAuthSite/Scripts/touryo/oauthimplicit.js

以下のようにOAuthImplicitGrantClient.cshtmlにコードを移植する。

-コード
 <a href="#" id="OAuthGetUserClaimsWebAPI" url="http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/userinfo">Get user claims</a>
 
 @section scripts{
     <script type="text/javascript">
 
         var fragment = "";
         var token = "";
 
         function CallOAuthAPI(url, httpMethod, postdata) {
             alert(
                 "<httpMethod>" + "\n" + httpMethod + "\n" +
                 "<url>" + "\n" + url + "\n" +
                 "<token>" + "\n" + token);
 
             $.ajax({
                 type: httpMethod,
                 url: url,
                 crossDomain: true,
                 headers: {
                     'Authorization': 'Bearer ' + token
                 },
                 data: postdata,
                 xhrFields: {
                     withCredentials: true
                 },
                 success: function (responseData, textStatus, jqXHR) {
                     alert(textStatus + ', ' + JSON.stringify(responseData));
                 },
                 error: function (responseData, textStatus, errorThrown) {
                     alert(textStatus + ', ' + errorThrown.message);
                 }
             });
         }
 
         $(function () {
             // フラグメントを取得し、
             fragment = getFragment();
             // フラグメントに access_token (Bearer Token) がある場合、
             if (fragment.access_token) {
 
                 // access_token (Bearer Token) を使用して
                 // ResourceServerのWebAPIにアクセスする。
                 token = fragment.access_token;
 
                 // 「access_token」(Bearer Token)が
                 // "露見"しないようwindow.location.hashを消去。
                 // ~~~~~~
                 window.location.hash = fragment.state || '';
                 
                 // OAuthGetUserClaimsWebAPI
                 $('#OAuthGetUserClaimsWebAPI').on('click', function () {
                     CallOAuthAPI($('#OAuthGetUserClaimsWebAPI').attr("url"), 'get', null)
                 });
             }
         });
 
         // -----------------------------------------------------------
         // フラグメント(#~の部分)を取得する。
         // -----------------------------------------------------------
         function getFragment() {
             // URLの「#」記号の後の部分を取得し、
             if (window.location.hash.indexOf("#") === 0) {
                 // # が1文字目にある場合
                 // 2文字目以降をobjectにparse。
                 return parseQueryString(window.location.hash.substr(1));
             } else {
                 // そうではない場合。
                 return {}; // 空
             }
         };
         
         // -----------------------------------------------------------
         // QueryStringをobjectにparseする。
         // -----------------------------------------------------------
         function parseQueryString(queryString) {
             //alert(queryString);
             var data = {},
                 pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;
         
             if (queryString === null) {
                 return data; // 空で返す。
             }
         
             // 分解して、
             pairs = queryString.split("&");
         
             // 詰めて、
             for (var i = 0; i < pairs.length; i++) {
                 pair = pairs[i];
                 separatorIndex = pair.indexOf("=");
         
                 if (separatorIndex === -1) {
                     escapedKey = pair;
                     escapedValue = null;
                 } else {
                     escapedKey = pair.substr(0, separatorIndex);
                     escapedValue = pair.substr(separatorIndex + 1);
                 }
         
                 key = decodeURIComponent(escapedKey);
                 value = decodeURIComponent(escapedValue);
         
                 // インデクサで。
                 data[key] = value;
             }
         
             // 返す。
             return data;
         }
 
     </script>
 }

-実行結果
>
#ref(3a.png,left,nowrap,3a,80%)

***注意事項 [#ma7eb138]
URLフラグメントを使用するため、Authorization Codeグラント種別と比べ、~
非常に、アクセストークンが画面に露見し易いので注意する。

*OpenID Connect [#xf70352f]
**Authorization Code Flow [#i3cda345]
OpenID ConnectのAuthorization Code Flowをテストする。

***スターター [#t97b9eb3]
上記の[[スターター>#fe72f177]]のScopeにopenidを加えるだけで、~
OpenID ConnectのAuthorization Code Flowをテストできる。

 <a href="http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=21c7769f16634dabaf14282602b9a5fc&response_type=code&scope=profile%20email%20phone%20address%20userid%20aaa%20openid&state=vj9NCxij4L">開始</a>

***コード [#mc27d8dc]
特に、id_tokenの検証に関して、以下のコードが参考になる。

-WebFormのredirectエンドポイント~
https://github.com/OpenTouryoProject/OpenTouryo/blob/develop/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Aspx/OAuth2/OAuth2AuthorizationCodeGrantClient.aspx.cs#L71

-MVCのredirectエンドポイント~
https://github.com/OpenTouryoProject/OpenTouryo/blob/develop/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Controllers/HomeController.cs#L189

-id_tokenの検証には、JwtToken.Verifyメソッド、DigitalSignX509.Verifyメソッドを使用している。
--JwtToken.Verifyメソッド~
https://github.com/OpenTouryoProject/OpenTouryo/blob/develop/root/programs/CS/Frameworks/Infrastructure/Public/Security/JWT_RS256.cs#L95
--DigitalSignX509.Verifyメソッド~
https://github.com/OpenTouryoProject/OpenTouryo/blob/develop/root/programs/CS/Frameworks/Infrastructure/Public/Security/DigitalSignX509.cs#L156

**Implicit Flow [#odb23e5a]
OpenID ConnectのImplicit Flowをテストする。

***スターター [#geda9bfa]
Implicit Flowでは、Scopeにopenidを加えるだけでなく、~
response_typeを、response_type=id_token token, id_tokenに変更する必要がある。

 <a href="http://(汎用認証サイトのアドレス:ポート)/MultiPurposeAuthSite/Account/OAuthAuthorize?client_id=21c7769f16634dabaf14282602b9a5fc&response_type=id_token%20token&scope=profile%20email%20phone%20address%20userid%20aaa%20openid&state=vj9NCxij4L">開始</a>

***コード [#lca0948f]
JavaScriptでid_tokenの検証をするには...。

WebCrypto APIなるものがあるもよう。

-WebCrypto APIでJSON Web Tokenの検証を試してみる - Qiita~
http://qiita.com/tomoyukilabs/items/faa66805a440f4b30cfb

-自堕落な技術者の日記 : W3C Web Cryptography APIとの~
果てしなき戦い(第2回 RSA署名生成と検証) - livedoor Blog(ブログ)~
http://blog.livedoor.jp/k_urushima/archives/1759093.html
>公開鍵のインポートと署名の検証

*SpringMVC(Java)でやる。 [#i5d3d94b]

***SpringMVC(Java) [#q2c66de7]
[[コチラ>https://dotnetdevelopmentinfrastructure.osscons.jp/index.php?Java%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%82]]を参考にする。

-Javaを書いてみる。 - .NET 開発基盤部会 Wiki~
https://dotnetdevelopmentinfrastructure.osscons.jp/index.php?Java%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%82

***コード [#hfcd67a5]
OAuth2.0、OpenID Connect のサンプル・コード(Redirectエンドポイント)

 package com.example.test1;
 
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Signature;
 import java.security.SignatureException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.interfaces.RSAPublicKey;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.Base64.Decoder;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.apache.http.HttpHeaders;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.EntityUtils;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.servlet.ModelAndView;
 
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
 
 @Controller
 public class HeloController {
 	
 	@RequestMapping(value="/", method=RequestMethod.GET)
 	public ModelAndView index(ModelAndView mav) {
 		mav.setViewName("index");
 		return mav;
 	}
 	
 	@RequestMapping(value="/", method=RequestMethod.POST)
 	public ModelAndView send(@RequestParam("text1")String str, ModelAndView mav) {
 		mav.setViewName(
 				"redirect:http://localhost:63359/MultiPurposeAuthSite/Account/OAuthAuthorize" 
 				+ "?client_id=084b7157a4d7427794012ee8a8e6d415" 
 				+ "&response_type=code" 
 				+ "&scope=profile%20email%20phone%20address%20openid"
 				+ "&state=q58aqOg3"
 				+ "&nonce=CiC1wEsurMkmMRBh");
 		return mav;
 	}
 	
 	@RequestMapping(value="/code", method=RequestMethod.GET)
 	public ModelAndView code(@RequestParam("code") String code, @RequestParam("state") String state, ModelAndView mav) {
 		
 		if(state.equals("q58aqOg3")) // CSRF(XSRF)対策のstateの検証は重要
 		{
 			try {
 				// Requestの準備
 				String host = "localhost";
 				String path1 = "/MultiPurposeAuthSite/OAuthBearerToken";
 				String path2 = "/MultiPurposeAuthSite/userinfo";
 				String username = "084b7157a4d7427794012ee8a8e6d415";
 				String password = "JxBaXLNFyK4lCawEY9_HPA2zzjyiLgIiV4MQ2uogYms";
 				
 				HttpHost httpHost = new HttpHost(host, 63359, "http");
 				HttpPost httpPost = new HttpPost(path1);
 				HttpClient client = HttpClientBuilder.create().build();
 				
 				String auth = username + ":" + password;
 				byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(Charset.forName("ISO-8859-1")));
 				String authHeader = "Basic " + new String(encodedAuth);
 				httpPost.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
 				
 				List<NameValuePair> requestParams = new ArrayList<>();
 				requestParams.add(new BasicNameValuePair("grant_type","authorization_code"));
 				requestParams.add(new BasicNameValuePair("code",code));
 				requestParams.add(new BasicNameValuePair("redirect_uri", StringEscapeUtils.unescapeHtml4("http://localhost:8090/code")));
 				
 				HttpResponse response = null;
 				
 				// Requestの発行
 				httpPost.setEntity(new UrlEncodedFormEntity(requestParams));
 				response = client.execute(httpHost, httpPost);
 				
 				// HttpStatusの確認
 				int status = response.getStatusLine().getStatusCode();
 				if (status == HttpStatus.SC_OK){	
 					
 					// responseの取得
 					String responseData = EntityUtils.toString(
 							response.getEntity(), StandardCharsets.UTF_8);
 					
 					// JSONのParse
 					Gson gson = new Gson();
 					Type type = new TypeToken<Map<String, String>>(){}.getType();
 					Map<String, String> map = gson.fromJson(responseData, type);
 					
 					String access_token = map.get("access_token");
 					//String token_type = map.get("token_type");
 					//String expires_in = map.get("expires_in");
 					//String refresh_token = map.get("refresh_token");
 					String id_token = map.get("id_token");
 					
 					// id_tokenの検証
 					String[] jwt = id_token.split("\\.");
 					
 					Decoder base64urlDecoder = Base64.getUrlDecoder();
 					
 					//String jwtHeaderString = new String(base64urlDecoder.decode(jwt[0]), "UTF-8");
 					String jwtClaimString  = new String(base64urlDecoder.decode(jwt[1]), "UTF-8");
 					//String jwtSignitureString  = new String(base64urlDecoder.decode(jwt[2]), "UTF-8");
 					
 					byte[] message = (jwt[0] + "." + jwt[1]).getBytes("UTF-8");
 					byte[] sign = base64urlDecoder.decode(jwt[2]);
 					
 					// JWT(RS-256の検証)
 					
 					// RSAによる署名と、その検証方法の例。
 					// 1. RSAキーペアを生成し、公開キー・非公開キーをおさめたPKCS12(*.p12)形式と、公開キーをおさめたX.509のDERファイル形式を生成する。 
 					// 2. PKCS12を読み取り、秘密キーでメッセージを署名する。 
 					// 3. DERを読み取り、公開キーでメッセージの署名をベリファイする。
 					// 手順1の、X.509の生成に、sunの非公開関数を用いている。
 					// 代替ライブラリとしてはbouncycastleなどがある。 手順2以降は標準APIだけで実装可。 · GitHub
 					// https://gist.github.com/seraphy/5359542
 					
 					// X509証明書から、RSA公開キーを復元する.
 					RSAPublicKey publicKey2;
 					try (InputStream is = new FileInputStream("C:\\root\\files\\resource\\X509\\RS256.cer")) {
 						X509Certificate x509 = null;
 						
 						try {
 							x509 = this.loadX509(is);
 						} catch (GeneralSecurityException e) {
 							// TODO Auto-generated catch block
 							e.printStackTrace();
 						}
 						
 						publicKey2 = (RSAPublicKey) x509.getPublicKey();
 					}
 					
 					// RSA公開キーで署名器を生成する.
 					Signature verifier = null;
 					boolean result = false;
 					
 					verifier = Signature.getInstance("SHA256withRSA");
 					verifier.initVerify(publicKey2);					
 					verifier.update(message);
 					result = verifier.verify(sign);
 					
 					if(result)
 					{
 						map = gson.fromJson(jwtClaimString, type);
 						String iss = map.get("iss");
 						String aud = map.get("aud");
 						String nonce = map.get("nonce");
 						String sub = map.get("sub");
 						String iat = map.get("iat");
 						String exp = map.get("exp"); //1505490503;
 						
 						if(
 								iss.equals("http://jwtssoauth.opentouryo.com")
 								&& aud.equals("084b7157a4d7427794012ee8a8e6d415")
 								&& nonce.equals("CiC1wEsurMkmMRBh")
 								&& (System.currentTimeMillis() / 1000L) <= Long.parseLong(exp))
 						{
 							// /userinfoへアクセス。
 							HttpGet httpGet = new HttpGet(path2);
 							client = HttpClientBuilder.create().build();
 							
 							authHeader = "Bearer " + access_token;
 							httpGet.setHeader(HttpHeaders.AUTHORIZATION, authHeader);
 							
 							// Requestの発行
 							response = client.execute(httpHost, httpGet);
 							
 							// HttpStatusの確認
 							status = response.getStatusLine().getStatusCode();
 							if (status == HttpStatus.SC_OK){	
 								
 								// responseの取得
 								responseData = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
 								
 								// JSONのParse
 								gson = new Gson();
 								type = new TypeToken<Map<String, String>>(){}.getType();
 								map = gson.fromJson(responseData, type);
 								sub = map.get("sub");
 							}
 						}
 					}
 				}
 				
 			} catch (NoSuchAlgorithmException e) {
 				e.printStackTrace();
 			} catch (InvalidKeyException e) {
 				e.printStackTrace();
 			} catch (SignatureException e) {
 				e.printStackTrace();
 			} catch (ClientProtocolException e) {
 				e.printStackTrace();
 			} catch (UnsupportedEncodingException e) {
 				e.printStackTrace();
 			} catch (IOException e) {
 				e.printStackTrace();
 			}
 		}
 		
 		mav.setViewName("index");
 		return mav;
 	}
 	
 	public X509Certificate loadX509(InputStream is) throws IOException, GeneralSecurityException {
 		CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
 		return (X509Certificate) certFactory.generateCertificate(is);
 	}
 }


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS