none
ロールベースセキュリティについて RRS feed

  • 質問

  • こんばんは。

    VB2005+SQLServerExpressにて開発を行っています。

    http://social.msdn.microsoft.com/Forums/ja-JP/vsgeneralja/thread/e5294974-7663-412e-9860-2d7dcfa7943a

    にて、質問をさせていただいていたのですが、普段はこちらの掲示板を利用させていただいているので、移動をさせていただきました。

    ユーザーにより、利用できる範囲を制限する方法を探しており、ロールベースセキュリティを利用するのがよいというアドバイスを
    いただきました。

    現在のWindowsユーザーを取得し、そのユーザーが所属する組み込みのグループを取得する方法はいろいろなホームページに
    のっているのですが、独自に作成をしたグループを取得する方法はないのでしょうか。

    ファイルサーバーを利用していることから、ユーザーが所属するグループによりアクセス管理をしているので、それと同じように
    利用できることが希望です。

    また、各ユーザーがどのロールに所属するかを任意に設定できるとのことですが、これはどこに記述をするものなのでしょうか。

    アプリケーションを起動するとログインフォームが開くようにしてあるので、このフォームのLoadイベントに記述をすればよいのかな?
    とも思っているのですが、どこに記述をするべきなのでしょうか。

    調べている最中に見つけたサンプルでは、どこに記述をするかはわからなかったのですが、各ユーザーがどのロールに所属するかを
    記述するコードがありました。
    ただ、この方法だとユーザーが増えるたびにコードを書き直す必要があるので、可能であれば、Windowsに自分で作成をした
    グループ名を取得できれば、それにより権限設定(ボタンの使用の可否など)を行うようなコードを記述できると思っています。

    どうか、アドバイスお願いします。
    2009年8月7日 12:11

回答

  • Windows 認証や Form 認証など、特定の認証機構に紐づかない場合に、汎用的なものとして利用できるのが GenericIdentity と GenericPrincipal になります。
    特定の認証機構に紐づいていないので、自分の好きな情報を持たせて利用できます。
    例えば、データベースに独自の認証情報を持っている際に、Identity と Principal を持たせたい場合などに利用できると思います。
    もちろん Generic を使わずに、Identity と Principal を拡張して独自のクラスを作るということも可能です。
    • 回答としてマーク TI-cb400 2009年8月9日 22:11
    2009年8月9日 13:01
  • >誰がどの時間帯にアプリケーションを利用したのか

    SQL Serverであればデータベースにログオン中のアカウントをSQL文で取得できるので、そいつを使ってDBにアクセス日時を記録すればいいでしょう。
    データベースにログオンすらできないユーザーであればデータベースのログに任せるか、自前でログを記録するかかな。

    >ユーザーの情報をDBに持ち、その情報をGenericPrincipalにコピーして利用する

    ユーザー情報を読み出すのをストアドやビューを使って、ログインユーザー以外の情報が見えないようにするならそれでもいいでしょう。
    SQL Serverだとログイン権限、データベースアクセス権限、テーブルやビューの読み書き権限などが細かく定義できますから、データベース側で権限を設定しておいてその権限の可否をIPrincipalに設定する方が良いいような気もしますが。
    #プログラムで権限の確認方法があったか覚えてないのでおかしなこと書いてるかも
    • 回答としてマーク TI-cb400 2009年8月9日 22:11
    2009年8月9日 16:11

すべての返信

  • 権限を与えたいドメイン\グループをSystem.Security.Principal.NTAccountを取得できます。
    System.Security.Principal.WellKnownSidTypeでとってもいいですし、ドメイン名とグループ名はコードに直接書いてもいいです。
    #ドメインはさすがに実行環境に合わせて取得しないといけないでしょうが。
            '実行中のユーザーの識別子取得
            Dim wid As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
    
            '所属しているグループの列挙
            Dim principal As System.Security.Principal.WindowsPrincipal = New System.Security.Principal.WindowsPrincipal(wid)
            For Each group As System.Security.Principal.SecurityIdentifier In wid.Groups
                Console.WriteLine(group.Translate(GetType(System.Security.Principal.NTAccount)))
            Next
    
            Console.WriteLine(String.Empty.PadLeft(40, "*"c))
    
            'グループ名を使ってグループに所属しているかを調べる
            If principal.IsInRole("BUILTIN\Administrators") Then
                Console.WriteLine("管理者です")
            Else
                Console.WriteLine("管理者ではありません")
            End If
    
            Console.WriteLine(String.Empty.PadLeft(40, "*"c))
    
            'WellKnownSidTypeでし世属しているか調べる
            Dim sidUser As System.Security.Principal.SecurityIdentifier = New System.Security.Principal.SecurityIdentifier(System.Security.Principal.WellKnownSidType.BuiltinUsersSid, Nothing)
            If principal.IsInRole(sidUser) Then
                Console.WriteLine("ユーザーです")
            Else
                Console.WriteLine("ユーザーではありません")
            End If
    
            Console.WriteLine(String.Empty.PadLeft(40, "*"c))
    
            'グループ識別子を取得しておいて、所属しているかを調べる
            'SecurityIdentifierを保存しておけば、毎回文字列で確認するより負荷が低い
            Dim nta As New System.Security.Principal.NTAccount("DomainName", "RoleName")
            Try
                Dim sid As System.Security.Principal.SecurityIdentifier = nta.Translate(GetType(System.Security.Principal.SecurityIdentifier))
    
                If principal.IsInRole("DomainName\RoleName") Then
                    Console.WriteLine("ドメインのグループに所属しています")
                Else
                    Console.WriteLine("ドメインのグループに所属していません")
                End If
            Catch ex As Exception
                Console.WriteLine("存在しないドメインもしくはグループです")
            End Try

    2009年8月8日 4:06
  • ご回答ありがとうございます。

    ヘルプを参考に何とか理解しようとしているのですが、なかなか理解が進みません。

    たとえば、独自に「A」というグループを作り、このグループに所属する「A-1」というユーザーを作成するとします。

    これに所属するかどうかを取得したいと思い、「’グループ識別氏を取得・・・」以下の部分の

    Dim nta As New System.Security.Principal.NTAccount("DomainName", "RoleName")



    Dim nta As New System.Security.Principal.NTAccount("A", "A-1")

    としてみたのですが、エラーとなります。(例外処理に飛んでしまいます。)

    そもそも、DomainName RoleNameが何をさしているのかというところから調べているのですが、具体例がなくよくわからないのが現状です。

    今まで自分で調べていたのですが、ご提示いただいたコードのどの部分を修正すると自分が希望している判定ができるのかが
    どうしてもわかりません。

    行いたいことは、現在ログインしているWindowsユーザーが独自に作成したどのグループに所属しているかを取得したいと思っています。
    それを元に、フォームごとにボタンなどの使用の可否を判定したいと思っています。

    また、もう1点わからないことは、今回ご提示いただいたコードを各フォームのLoadイベントに記述しなければならないのか、
    それとも、アプリケーション起動時に取得し、どのフォームを開いたときでもどのグループに所属しているかという情報にアクセスでき、
    フォームを開く際の判定に利用することができるのかどうかという点です。

    どうか、アドバイスお願いします。
    2009年8月8日 7:50
  • DomainはWindowsドメインと思ってください。RoleNameがグループ名になります。

    たとえばドメイン無しのローカルなUsersグループであれば
    Dim nta As New NTAccount("" , "Users" )
    で取得できます。。

    WindowsドメインがDomainAという名前のUsersグループであれば
    Dim nta As New NTAccount("DomainA" , "Users" )
    で取得します。

    Aというグループなら
    Dim nta As New NTAccount("DomainA" , "A" )
    で取得します。

    A-1というユーザーのIDとしては、A-1というユーザーで実行していればSystem.Security.Principal.WindowsIdentity.GetCurrent()でWindowsIdntityが取得できますし、さらにWindowsPrincipalも取得できます。
    グループが取得できたら、WindowsPrincipalのIsInRoleでこのWindowsPrincipalがグループに所属しているかを調べられます。
    #グループに所属させた直後はログインしなおさないとグループが反映されないことがあるかも。

    どこにこれらの確認コードを記述するかはプログラム次第です。
    たとえばフォームのボタンをはじめから無効にしたいのでしたら、Loadイベント中で確認してボタンを無効にしてもいいですし。
    あるいはボタンは有効にしたまま、ボタンのClickイベント中で確認を行って特定の処理を無効にするのも自由です。
    2009年8月8日 9:32
  • Windows の認証情報から独立したグループ情報を持ちたいのであれば、GenericPrincipal と GenericIdentity を使う方が簡単かもしれません。

    方法 : GenericPrincipal オブジェクトと GenericIdentity オブジェクトを作成する

    アプリケーションのログイン処理でユーザーを特定した時に、Windows の認証情報を Generic????? にコピーするイメージになると思います。
    2009年8月8日 11:19
  • ご回答ありがとうございます。

    gekkaさんがおっしゃるとおりログインをしなおしたら、独自に作成をしたグループ名も取得できました。

    おかげさまでユーザー別のフォームの管理が可能になりました。

    少し、横道にそれるので別の質問にしたほうがよいかとは思ったのですが、可能であれば誰がどの時間帯に
    アプリケーションを利用したのか、ということも管理したいと考えています。

    最終目標としては、どのパソコンからであってもデータを利用できるようにサーバーのユーザー情報を
    今回のように取得できればと考えているのですが、これを実現する方法が totojoさんがご提示してくださった
    方法と解釈してよろしいでしょうか。

    また、その際にユーザーの情報をDBに持ち、その情報をGenericPrincipalにコピーして利用するということは
    問題がないのでしょうか。(当然、そのユーザー情報を見られないようにする方法は考えなければなりませんが)

    どうか、アドバイスお願いいたします。
    2009年8月8日 20:37
  • Windows 認証や Form 認証など、特定の認証機構に紐づかない場合に、汎用的なものとして利用できるのが GenericIdentity と GenericPrincipal になります。
    特定の認証機構に紐づいていないので、自分の好きな情報を持たせて利用できます。
    例えば、データベースに独自の認証情報を持っている際に、Identity と Principal を持たせたい場合などに利用できると思います。
    もちろん Generic を使わずに、Identity と Principal を拡張して独自のクラスを作るということも可能です。
    • 回答としてマーク TI-cb400 2009年8月9日 22:11
    2009年8月9日 13:01
  • >誰がどの時間帯にアプリケーションを利用したのか

    SQL Serverであればデータベースにログオン中のアカウントをSQL文で取得できるので、そいつを使ってDBにアクセス日時を記録すればいいでしょう。
    データベースにログオンすらできないユーザーであればデータベースのログに任せるか、自前でログを記録するかかな。

    >ユーザーの情報をDBに持ち、その情報をGenericPrincipalにコピーして利用する

    ユーザー情報を読み出すのをストアドやビューを使って、ログインユーザー以外の情報が見えないようにするならそれでもいいでしょう。
    SQL Serverだとログイン権限、データベースアクセス権限、テーブルやビューの読み書き権限などが細かく定義できますから、データベース側で権限を設定しておいてその権限の可否をIPrincipalに設定する方が良いいような気もしますが。
    #プログラムで権限の確認方法があったか覚えてないのでおかしなこと書いてるかも
    • 回答としてマーク TI-cb400 2009年8月9日 22:11
    2009年8月9日 16:11
  • ご回答ありがとうございます。

    ご教授いただいた内容を元に、今後はテストをしながら進めて生きたいと思っています。

    また、その上でわからないことが出てきたら質問をさせていただきたいと思います。

    本当にありがとうございました。
    2009年8月9日 22:11