2018年11月10日土曜日

IdentityServer4 で ログインとロールベースの認証を行うまで

ユーザ認証やら何やらで IdentityServer4 を調べて、Roleベースの認証がとりあえずできるようになったので、手順を記載したもの。
コレが良い手法なのかはわからないが、ともかく、一番余分なコードを書かないで済みそうな方法だとは思う。

■概要

IdentityServer4の公式が提示しているサンプルを修正して、Roleベースの認証の動作確認を行うまでの手順。

■前提条件

  • 以下の環境で動作を確認: Visual Studio 2017 .NET Core 2.1 IdentiryServer4

■修正のベースにしたサンプルの準備

  • 以下を落としてくる: https://github.com/IdentityServer/IdentityServer4.Samples
  • 上記で、以下のフォルダに入っているソリューションを修正元として使う: IdentityServer4.Samples\Quickstarts\6_AspNetIdentity
  • ダブルクリックで、.sln ファイルを開いて、修正。

■IdentityServer側プロジェクトの修正内容

「IdentityServerWithAspNetIdentity」プロジェクトに、ユーザ認証にかかわる処理がまとまっているので、そこのファイルを修正する。

◆ユーザの準備

  • SeedDataで、ログインユーザの作成を行っているので、そのユーザのClaimに、何かRoleっぽい物を追加する。
    サンプル追加例)
new Claim("mvc_roles", "admin")

※なお、この例では、”bob”にだけ”admin”権限をつけた。

◆Scope 追加

  • Config で IdentityServer4 の OpenID にかかわる色々の設定が行われているので、それも修正
    GetIdentityResources メソッドで戻している IdentityResources に、ユーザに追加したRoleっぽいClaimの名前を追加します。(これをしないと、クライアントから取得できない
    サンプル追加例)
               new IdentityResource()
               {
                   Name = "role_for_mvc",
                   DisplayName = "権限",
                   UserClaims = { "mvc_roles" },
                   Required = true
               }

  • “UserClaims” に、SeedData で追加したロール向けClaim の名前を設定。
     GetClients メソッドで返している Client の内、MVC クライアントに対応する「ClientId = "mvc"」の AllowedScopes に、 上記で追加した IdentityResources の名前を追加。
    修正後のコード例)
                   AllowedScopes =
                   {
                       IdentityServerConstants.StandardScopes.OpenId,
                       IdentityServerConstants.StandardScopes.Profile,
                       "api1",
                       "role_for_mvc"
                   },

これで、IdentityServer4 側の修正は完了。

■MVCクライアント側の修正内容

クライアント側に、Roleベースの認証を試せるだけの処理を追記。

◆プロジェクト設定変更

  • SDK を ASP.NET Core 2.1 に変更。(2.1にしかないクラスを使いたいので) 1. “MvcClient”プロジェクトを右クリックし、「プロパティ」を選択 2. アプリケーションのターゲットフレームワークで「.NET Core 2.1」を選択
    3. “MvcClient”プロジェクトの「依存関係」を右クリックし、「NuGetパッケージの管理」を選択 4. Nuget パッケージの管理で、全てのパッケージを更新。

◆Startup の修正

  • Startup の ConfigureServices メソッドを修正し、追加したClaimを取得するようにする。 修正例)
                   options.Scope.Add("api1");
                   options.Scope.Add("offline_access");
                   options.Scope.Add("role_for_mvc"); // 追加した行

                   options.ClaimActions.Add(new MapAllClaimsAction()); // 追加した行

  • 追加したClaimでRoleの判定をするように変更。上記の修正を加えた行の下に、以下も追加:
                   options.TokenValidationParameters = new TokenValidationParameters
                   {
                       RoleClaimType = "mvc_roles"
                   };

◆Controller の修正

  • 実験のため、HomeController に、Roleをくっつけた Authorize 属性のあるメソッドを追加(ここではSecureメソッドをコピペして改変)
    例:追加したメソッド)
       [Authorize(Roles ="admin")]
       public IActionResult SecureWithRole()
       {
           ViewData["Message"] = "Secure page(with role).";

           return View("Secure");
       }


修正は以上。
これで、動作の確認ができるようになったはず。

■蛇足:動かし方

  • とりあえずの動作確認方法 1. 下記プロジェクトのWebサーバをすべて起動
     IdentityServerWithAspNetIdentity  MvcClient  Api 2. http://localhost:5002 にアクセス 3. ヘッダ部分のSecure リンクをクリックすると、ログイン画面が出てくるはずなので、ログイン(SeedDataが登録されていれば、bob か alice でログインできるはず) 4. ユーザ情報へのアクセス許可を求められるので、許可して進む 5. Secure画面が表示される(Authenticate属性だけの画面) 6. Role で保護された画面を、URLを変更して、表示する(この例だとhttp://localhost:5002/SecureWithRole に変更してアクセス) 7. ログインしたユーザに権限があれば、問題なくアクセスできる(はず)。ユーザをRoleが無い側のユーザに切り替えてアクセスすると、とりあえずアクセスが拒否される(はず) 
  • なお、各サーバは Visual Studio 上から動かすより、コマンドライン上から動かしてしまった方が多分、楽だと思われる: コマンドプロンプトで各プロジェクトのフォルダに移動したうえで: dotnet run あるいは: dotnet run -p (各プロジェクトのフォルダパス)

参考情報:

ほぼこのブログのまま - http://benfoster.io/blog/asp-net-identity-role-claims
API:https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.oauth.claims.mapallclaimsaction?view=aspnetcore-2.1
ドキュメント:http://docs.identityserver.io/en/release/

以上。

2018年10月27日土曜日

FitSharp を .NET Core で実行してみる手順

Ubuntu上でFitNesseをインストール、.NETCoreのプロジェクトにFitSharpを追加して、テストページを作って、とりあえず実行してみるまでの手順。
(コーディングはWindows環境下でやっていたので、途中にWindowsでの手順含む。スイマヘン;)
前提条件: Java と.NET Core のSDKはインストール済

FitNesseのインストール:


FitNesse は、”fitnesse-standalone.jar” と Javaさえあれば、動作する。配置するフォルダは、任意で問題ない。Windows でも同様。。


実行コマンド:
cd /usr/local/bin
mkdir fitnesse
cd fitnesse
wget "http://fitnesse.org/fitnesse-standalone.jar?responder=releaseDownload&release=20180127" -O fitnesse-standalone.jar

※念のため:fitnesse-standalone.jar を配置するフォルダは上記以外の場所でも問題ないです※


FitNesse起動:

java -jar fitnesse-standalone.jar -p 8989

-p で指定しているポート番号で動作します。上記の番号は適当です。空いてる番号であれば、何でも良い。

アクセス:
http://(貴方のIP):8989

こんな感じに表示されるはず:


FitSharp向けプロジェクトのセットアップ


.NET Core でビルドされているプロジェクトであれば、FitSharp でテストケースを実行できるはず。
(ここだけWindows;)

プロジェクトに必要な設定など


依存関係で、 Nuget パッケージの FitSharp を追加する。
プロジェクトの「依存関係」を右クリック > NuGetパッケージの管理をクリック

開いたウィンドウで参照をクリックして、「FitSharp」と入力して、選択:

右側で「インストール」をクリック

動作確認向けに、テストクラスを作る


fit.XXXXFixture みたいなクラスを必要に応じて継承したクラスを作る。
FitSharp の XXXFixture の説明は以下ページ:

とりあえず、動作確認さえできれば良いという程度のものを。。
例)
    public class Class1 : fit.ColumnFixture

    {

           public int value1;

           public int value2;



       public int Add()

       {

               return value1 + value2;

       }

    }


FitNesse 向けの設定ファイルを作る


プロジェクト直下に、FitSharp実行向けの設定を保持する.xmlファイルを作る。
ここでは適当に「mysuiteconfig.xml」とゆー名前で作ったものと仮定する。。
こんな中身:
<?xml version="1.0" encoding="utf-8" ?>

<suiteConfig>

 <ApplicationUnderTest>

    <AddAssembly>(プロジェクトまでのパス)/bin/Debug/netcoreapp2.1/(プロジェクト名).dll</AddAssembly>

    <AddNamespace>(テスト対象の名前空間名)</AddNamespace>

 </ApplicationUnderTest>

 <Settings>

    <Runner>fitnesse.fitserver.FitServer</Runner>

 </Settings>

</suiteConfig>


ここで、最低限、テスト対象のアセンブリのパスと、FitSharpのテストランナーを指定する必要がある。パスは、FitNesseを実行する環境のパスを記載のこと。

ここまでに作ったプロジェクトを、FitNesse を置いた環境に持っていき、ビルド。
ソリューションを配置しているフォルダまで cd で移動して、dotnet build
 を実行で、ビルドができる。

FitNesseで試験向けのページ追加


FitNesse 上のWikiページで「Add > TestPage」をクリック


ページの内容(作成例):

!define COMMAND_PATTERN {%m (FitSharpの配置されているディレクトリ)/Runner.dll -c (プロジェクトのディレクトリ)/mysuiteconfig.xml %p}
!define TEST_RUNNER {dotnet}

|Class1|
|value1|value2|Add?|
|10    |2     |12  |
|12    |3     |15  |
|100   |4     |104 |

※補足:
FitSharp の dll は、ビルドしたならば以下辺りにあるはず:
Ubuntu:
$HOME/.nuget/packages/fitsharp/2.7.0/lib/netcoreapp2.0/

Win:
%HOMEPATH%\.nuget\packages\fitsharp\2.7.0\lib\netcoreapp2.0



こんなページとして表示されるはず:


全てが正しく設定されていれば、左上の「Test」リンクをクリックで、テストが実行されるはず。。 
なのだが、FitSharp 2.7.0時点で、Ubuntu18.04(Hyper-V上のVM)では正しく動かなかった。"fit.dll"が正しくロードされないとか、そんなエラーが起きている方は、下に記載した蛇足の情報が参考になる…かも。

参考:

FitSharp の設定を説明したページ:



蛇足の情報:UbuntuではFitSharpが簡単には動かなかった


発生した現象:


Windows 環境下では,NET Coreで動作させることが出来たが、 どうも、 Ubuntu18.04(Hyper-V上のVM)環境下では、うまくテストを実行できなかった。(fit.dll のアセンブリを読み込に失敗したようなエラーが起きる) 。多分、FitSharp version2.7.0固有の問題。


とりあえずの対応方法:

FitNesse を起動しているフォルダ配下に FitSharp のdllをコピーして置いてしまう。

簡単な例)
FitSharp のdll が保存されてる場所:
/home/hoge/.nuget/packages/fitsharp/2.7.0/lib/netcoreapp2.0/

FitNesseを実行したフォルダ:
/usr/local/bin/fitnesse

以下にfitSharpのdll(fit, fitSharp, Runner)をコピーする:
/usr/local/bin/fitnesse/home/hoge/.nuget/packages/fitsharp/2.7.0/lib/netcoreapp2.0/

上記のようにFitNesse実行中のフォルダに対応するフォルダを作ってdllをコピーすれば、動くことは動くはず。

原因(多分):


ApplicationUnderTestクラスの内部クラスAssembliesクラスの AddAssembly メソッドで、 Windows 環境専門のロジックになっているから??
この部分:
var assemblyName = name.StartsWith("file:///") ? name.Substring(8) : name;

上記コードの”name”にはアセンブリのCodeBase の中身が設定されるが、自環境ではCodeBaseは以下のように戻ってきた(パスの中身は気にしないで):
Win:
file:///C:/Users/mgggt/sources/fitsharp-master/source/netcore/Runner/bin/Debug/netcoreapp2.0/fit.dll

Ubuntu(Hyper-V上のVM):
file:///var/lib/jenkins/workspace/DotNetCoreWebSample/FTest/fs/fit.dll


0ベースの8文字目スタートだと、Ubuntu側が相対パス扱いになって、正しく読み取れない。で、エラーになる(んだと思う。VMとかその他環境要因があるかは調べてない)。


その他対応案:


エラーの原因(?)になっていると思われる name.substring(8) を new Uri(name).LocalPath に置き換え、ビルドして.dll作り直すのが一番楽と言う気がした。。
(一応動作することは確認)
こうする:
var assemblyName = name.StartsWith("file:///") ? new Uri(name).LocalPath : name;


参考情報:

上記のパス変換方法をこたえていた回答部分: