.. Adding Authorization .. _wiki2_adding_authorization: ==================== 認証を追加する ==================== .. :app:`Pyramid` provides facilities for :term:`authentication` and .. :term:`authorization`. We'll make use of both features to provide security .. to our application. Our application currently allows anyone with access to .. the server to view, edit, and add pages to our wiki. We'll change that .. to allow only people who possess a specific username (`editor`) .. to add and edit wiki pages but we'll continue allowing anyone with access to .. the server to view pages. :app:`Pyramid` は :term:`authentication` と :term:`authorization` の ための機能を提供しています。アプリケーションにセキュリティを追加する ためにこれら両方の機能を利用します。私たちのアプリケーションは現在、 サーバーにアクセスできる誰もが wiki ページを見たり、編集したり、 追加したりすることが可能です。特定のユーザー名 (`editor`) を持つ限られた 人々だけに wiki ページの追加や編集を許可するようにアプリケーションを 変更してみましょう。しかし、依然としてサーバーにアクセスできる誰でも ページを見ることは可能です。 .. We will do the following steps: 次のステップで行います: .. * Add a :term:`root factory` with an :term:`ACL` (``models.py``). .. * Add an :term:`authentication policy` and an :term:`authorization policy` .. (``__init__.py``). .. * Add an authentication policy callback (new ``security.py`` module). .. * Add ``login`` and ``logout`` views (``views.py``). .. * Add :term:`permission` declarations to the ``edit_page`` and ``add_page`` .. views (``views.py``). .. * Make the existing views return a ``logged_in`` flag to the renderer (``views.py``). .. * Add a login template (new ``login.pt``). .. * Add a "Logout" link to be shown when logged in and viewing or editing a page .. (``view.pt``, ``edit.pt``). * ACL を持つ :term:`root factory` を追加 (``models.py``) * :term:`authentication policy` と :term:`authorization policy` を追加 (``__init__.py``) * 認証ポリシーコールバックを追加 (新しい ``security.py`` モジュール) * ``login`` および ``logout`` ビューを追加 (``views.py``) * ``edit_page`` および ``add_page`` ビューに :term:`permission` 宣言を 追加 (``views.py``) * 既存のビューがレンダラーに ``logged_in`` フラグを返すように修正 (``views.py``) * ログインテンプレートを追加 (新しい ``login.pt``) * "Logout" リンクを追加して、ログイン中にページを閲覧または編集している ときに表示されるようにする (``view.pt``, ``edit.pt``) .. The source code for this tutorial stage can be browsed at .. `http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki2/src/authorization/ .. `_. このチュートリアルステージのソースコードを以下の場所で閲覧することができます。 `http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki2/src/authorization/ `_. .. Adding A Root Factory ルートファクトリを追加する ~~~~~~~~~~~~~~~~~~~~~~~~~~ .. Open ``models.py`` and add the following statements: ``models.py`` を開き、以下のような文を追加してください。 .. literalinclude:: src/authorization/tutorial/models.py :lines: 1-4,35-39 :linenos: :language: python .. We're going to start to use a custom :term:`root factory` within our .. ``__init__.py`` file. The objects generated by the root factory will .. be used as the :term:`context` of each request to our application. .. Those context objects will be decorated with security .. declarations. When we use a custom root factory to generate .. our contexts, we can begin to make use of the declarative security .. features of :app:`Pyramid`. ``__init__.py`` ファイル内でカスタム :term:`root factory` を使用する ことにします。ルートファクトリによって生成されたオブジェクトは、 アプリケーションへの各リクエストの :term:`context` として使用されます。 この context オブジェクトは、 セキュリティ宣言でデコレートされます。コンテキストを生成するカスタム ルートファクトリの使用すると、 :app:`Pyramid` の宣言的な セキュリティ機能を利用することができるようになります。 .. We'll modify our ``__init__.py``, passing in a :term:`root factory` to our .. :term:`Configurator` constructor. We'll point it at the new class we created .. inside our ``models.py`` file. :term:`Configurator` コンストラクタに :term:`root factory` を渡すように ``__init__.py`` を修正します。それを ``models.py`` ファイルの内部で 作成する新しいクラスに向けます。 .. The ``RootFactory`` class we've just added will be used by :app:`Pyramid` to .. construct a ``context`` object. The context is attached to the request .. object passed to our view callables as the ``context`` attribute. たった今追加した ``RootFactory`` クラスは、 ``context`` オブジェクトを 構築するために :app:`Pyramid` によって使用されます。コンテキストは、 ビュー callable に渡された request オブジェクトに ``context`` 属性として 取り付けられています。 .. The context object generated by our root factory will possess an ``__acl__`` .. attribute that allows :data:`pyramid.security.Everyone` (a special principal) .. to view all pages, while allowing only a :term:`principal` named .. ``group:editors`` to edit and add pages. The ``__acl__`` attribute attached .. to a context is interpreted specially by :app:`Pyramid` as an access control .. list during view callable execution. See :ref:`assigning_acls` for more .. information about what an :term:`ACL` represents. ルートファクトリによって生成された context オブジェクトは、 :data:`pyramid.security.Everyone` (特別の principal) がすべてのページを 閲覧することを許可する一方、 ``group:editors`` という名前の :term:`principal` だけがページを編集したり追加したりすることを許可する ``__acl__`` 属性を所有します。コンテキストに取り付けられた ``__acl__`` 属性は、ビュー callable の実行中にアクセスコントロールリストとして :app:`Pyramid` によって特別に解釈されます。 :term:`ACL` が何を表わすかに ついての詳細は :ref:`assigning_acls` を参照してください。 .. .. note:: .. Although we don't use the functionality here, the ``factory`` used .. to create route contexts may differ per-route as opposed to globally. See .. the ``factory`` argument to .. :meth:`pyramid.config.Configurator.add_route` for more info. .. note: ここではその機能を使いませんが、ルートコンテキストを生成するために 使われる ``factory`` は、グローバルにする代わりにルート毎に異なって いても構いません。より多くの情報については、 :meth:`pyramid.config.Configurator.add_route` への ``factory`` 引数 を参照してください。 .. We'll pass the ``RootFactory`` we created in the step above in as the .. ``root_factory`` argument to a :term:`Configurator`. 上記のステップで作成した ``RootFactory`` は、 ``Configurator`` への ``root_factory`` 引数として渡します。 .. Add an Authorization Policy and an Authentication Policy 認証ポリシーと認可ポリシーを追加する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. We're going to be making several changes to our ``__init__.py`` file which .. will help us configure an authorization policy. ``__init__.py`` ファイルに、認可ポリシーを設定するのを助けるいくつかの 変更を加えていきます。 .. For any :app:`Pyramid` application to perform authorization, we need to add a .. ``security.py`` module (we'll do that shortly) and we'll need to change our .. ``__init__.py`` file to add an :term:`authentication policy` and an .. :term:`authorization policy` which uses the ``security.py`` file for a .. *callback*. :app:`Pyramid` アプリケーションが認可を行なうために、 ``security.py`` モジュールを追加する必要があります (私たちもまもなく追加します)。また、 ``security.py`` ファイルを *コールバック* に使用する :term:`authentication policy` および :term:`authorization policy` を 追加するために ``__init__.py`` ファイルを変更する必要があります。 .. We'll enable an ``AuthTktAuthenticationPolicy`` and an ``ACLAuthorizationPolicy`` .. to implement declarative security checking. Open ``tutorial/__init__.py`` and .. add these import statements: 宣言的なセキュリティ検査を実装するため、 ``AuthTktAuthenticationPolicy`` と ``ACLAuthorizationPolicy`` を有効にします。 ``tutorial/__init__.py`` を開いて、これらのインポート文を追加してください: .. literalinclude:: src/authorization/tutorial/__init__.py :lines: 2-3,7 :linenos: :language: python .. Now add those policies to the configuration: そうしたら、設定にこれらのポリシーを加えてください: .. literalinclude:: src/authorization/tutorial/__init__.py :lines: 16-22 :linenos: :language: python .. Note that the .. :class:`pyramid.authentication.AuthTktAuthenticationPolicy` constructor .. accepts two arguments: ``secret`` and ``callback``. ``secret`` is a string .. representing an encryption key used by the "authentication ticket" machinery .. represented by this policy: it is required. The ``callback`` is a .. ``groupfinder`` function in the current directory's ``security.py`` file. We .. haven't added that module yet, but we're about to. :class:`pyramid.authentication.AuthTktAuthenticationPolicy` コンストラクタ は 2 つの引数を受け付けます: ``secret`` と ``callback`` です。 ``secret`` は、 このポリシーによって表わされる「認証チケット」機構によって使用される 暗号鍵を表わす文字列です: これは必須です。 ``callback`` はカレントディレクトリ の ``security.py`` ファイル中の ``groupfinder`` 関数です。そのモジュールは まだ追加していませんが、それはこれからやります。 .. Viewing Your Changes 変更内容を確認する -------------------- .. When we're done configuring a root factory, adding a authentication and .. authorization policies, and adding routes for ``/login`` and ``/logout``, .. your application's ``__init__.py`` will look like this: ルートファクトリの設定、認証および認可ポリシーの追加、 ``/login`` および ``/logout`` のためのルート追加が終わると、アプリケーションの ``__init__.py`` はこのようになっているでしょう: .. literalinclude:: src/authorization/tutorial/__init__.py :linenos: :emphasize-lines: 2-3,7,16-18,20-22,25-26 :language: python .. Adding an authentication policy callback 認証ポリシーコールバックを追加する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. Add a ``tutorial/security.py`` module within your package (in the same .. directory as :file:`__init__.py`, :file:`views.py`, etc.) with the .. following content: パッケージ内 (:file:`__init__.py` や :file:`views.py` などと同じディレクトリ 内) に ``tutorial/security.py`` モジュールを次の内容で追加してください: .. literalinclude:: src/authorization/tutorial/security.py :linenos: :language: python .. The ``groupfinder`` function defined here is an :term:`authentication policy` .. "callback"; it is a callable that accepts a userid and a request. If .. the userid exists in the system, the callback will return a sequence .. of group identifiers (or an empty sequence if the user isn't a member .. of any groups). If the userid *does not* exist in the system, the .. callback will return ``None``. In a production system, user and group .. data will most often come from a database, but here we use "dummy" .. data to represent user and groups sources. Note that the ``editor`` .. user is a member of the ``group:editors`` group in our dummy group .. data (the ``GROUPS`` data structure). ここで定義した ``groupfinder`` 関数は、 :term:`authentication policy` 「コールバック」です; それは userid と request を受け取る callable です。 userid がシステムに存在すれば、コールバックはグループ識別子のシーケンス (ユーザがどのグループのメンバーでもなければ空のシーケンス) を返します。 userid がシステムに存在しなければ、コールバックは ``None`` を返します。 プロダクションシステムでは、ユーザとグループデータは、ほとんどの場合 データベースから取得されますが、ここではユーザとグループのソースを表わすために 「ダミーの」データを使用します。 ``editor`` ユーザは、ダミーのグループ データ (``GROUPS`` データ構造) 中の ``group:editors`` グループのメンバー であることに注目してください。 .. We've given the ``editor`` user membership to the ``group:editors`` by .. mapping him to this group in the ``GROUPS`` data structure (``GROUPS = .. {'editor':['group:editors']}``). Since the ``groupfinder`` function .. consults the ``GROUPS`` data structure, this will mean that, as a .. result of the ACL attached to the :term:`context` object returned by .. the root factory, and the permission associated with the ``add_page`` .. and ``edit_page`` views, the ``editor`` user should be able to add and .. edit pages. ``GROUPS`` データ構造の中で ``editor`` ユーザを ``group:editors`` グルー プにマッピングする (``GROUPS = {'editor':['group:editors']}``) ことにより、 ``editor`` ユーザを ``group:editors`` に所属させました。 ``groupfinder`` 関数が ``GROUPS`` データ構造を参照するので、これが意味 するのは、ルートファクトリによって返された :term:`context` オブジェクトに 取り付けられた ACL と ``add_page``, ``edit_page`` ビューに関連した許可の 結果、 ``editor`` ユーザがページの追加や編集ができるようになるということです。 .. Adding Login and Logout Views ログインとログアウトのビューを追加する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. To our ``views.py`` we'll add a ``login`` view callable which renders a login .. form and processes the post from the login form, checking credentials. ``views.py`` に、ログインフォームをレンダリングして、ログインフォーム からのポストを処理して認証情報 (credential) をチェックする ``login`` ビュー callable を付け加えます。 .. We'll also add a ``logout`` view callable to our application and .. provide a link to it. This view will clear the credentials of the .. logged in user and redirect back to the front page. さらに、アプリケーションに ``logout`` ビュー callable を加えて、 それへのリンクを提供します。このビューは、ログインユーザの 資格をクリアして、フロントページにリダイレクトします。 .. The ``login`` view callable will look something like this: ``login`` ビュー callable は次のようになります: .. literalinclude:: src/authorization/tutorial/views.py :lines: 89-115 :linenos: :language: python .. The ``logout`` view callable will look something like this: ``logout`` ビュー callable は次のようになります: .. literalinclude:: src/authorization/tutorial/views.py :lines: 117-121 :linenos: :language: python .. The ``login`` view callable is decorated with two decorators, a .. ``@view_config`` decorator, which associates it with the ``login`` .. route, and a ``@forbidden_view_config`` decorator which turns it in to .. an :term:`exception view`. The one which associates it with the .. ``login`` route makes it visible when we visit ``/login``. The other .. one makes it a :term:`forbidden view`. The forbidden view is .. displayed whenever Pyramid or your application raises an .. :class:`pyramid.httpexceptions.HTTPForbidden` exception. In this .. case, we'll be relying on the forbidden view to show the login form .. whenver someone attempts to execute an action which they're not yet .. authorized to perform. ``login`` ビュー callable は 2 つのデコレータ、 ``login`` ルートに関連 付ける ``@view_config`` と :term:`exception view` に変換する ``@forbidden_view_config`` でデコレートされています。 ``login`` ルートに 関連付けるものは、 ``/login`` を訪れたときにそれを目に見えるようにします。 他のものはそれを :term:`forbidden view` にします。 forbidden view は、 Pyramid またはアプリケーションが :class:`pyramid.httpexceptions.HTTPForbidden` 例外を上げる場合に常に 表示されます。この場合、誰かがまだ行なうことを許可されていない行為を実行 しようとした場合に常にログインフォームを表示するために、 forbidden view に依存します。 .. The ``logout`` view callable is decorated with a ``@view_config`` decorator .. which associates it with the ``logout`` route. This makes it visible when we .. visit ``/logout``. ``logout`` ビュー callable は、 ``logout`` ルートに関連付ける ``@view_config`` デコレータでデコレートされます。これは、 ``/logout`` を訪れたときにそれを目に見えるようにします。 .. We'll need to import some stuff to service the needs of these two functions: .. the ``pyramid.view.forbidden_view_config`` class, a number of values from the .. ``pyramid.security`` module, and a value from our newly added .. ``tutorial.security`` package. Add the following import statements to the .. head of the ``views.py`` file: これら 2 つの関数に必要なものを提供するために、いくつかの値をインポート する必要があるでしょう: ``pyramid.view.forbidden_view_config`` クラス、 ``pyramid.security`` モジュールからの多くの値、そして新しく追加した ``tutorial.security`` パッケージからの値です。次のインポート文を ``views.py`` ファイルの先頭に加えてください: .. literalinclude:: src/authorization/tutorial/views.py :lines: 9-18,24-25 :linenos: :language: python .. Changing Existing Views 既存のビューを変更する ~~~~~~~~~~~~~~~~~~~~~~~ .. Add permision declarations パーミッション宣言を追加する ---------------------------- .. Then we need to change each of our ``view_page``, ``edit_page`` and .. ``add_page`` view callables in ``views.py``. Within each of these views, .. we'll need to pass a "logged in" parameter to its template. We'll add .. something like this to each view body: 次に、 ``views.py`` の中の ``view_page``, ``edit_page``, ``add_page`` ビュー callable の各々を変更する必要があります。これらの各ビューの中では、 "logged in" パラメーターをテンプレートへ渡す必要があります。 各ビュー本体にこのようなものを加えます: .. code-block:: python :linenos: from pyramid.security import authenticated_userid logged_in = authenticated_userid(request) .. Return a logged_in flag to the renderer logged_in フラグをレンダラーに返す --------------------------------------- .. We'll then change the return value of these views to pass the resulting .. ``logged_in`` value to the template, e.g.: そして、その結果の ``logged_in`` の値をテンプレートへ渡すために、これら のビューの返り値を変更します。例えば: .. code-block:: python :linenos: return dict(page = page, content = content, logged_in = logged_in, edit_url = edit_url) .. We'll also need to add a ``permission`` value to the ``@view_config`` .. decorator for each of the ``add_page`` and ``edit_page`` view callables. For .. each, we'll add ``permission='edit'``, for example: さらに、 ``add_page`` および ``edit_page`` ビュー callable の各々のための ``@view_config`` デコレータに ``permission`` 値を加える必要があるでしょう。 各々について、例えば ``permission='edit'`` を加えます: .. code-block:: python :linenos: @view_config(route_name='edit_page', renderer='templates/edit.pt', permission='edit') .. See the ``permission='edit'`` we added there? This indicates that the view .. callables which these views reference cannot be invoked without the .. authenticated user possessing the ``edit`` permission with respect to the .. current :term:`context`. そこに加えられた ``permission='edit'`` を見てください。これは、これらの ビューが参照するビュー callable を、現在の :term:`context` に関して ``edit`` パーミッションを所有する認証されたユーザなしでは起動することが できない、ということを示します。 .. Adding these ``permission`` arguments causes Pyramid to make the .. assertion that only users who possess the effective ``edit`` .. permission at the time of the request may invoke those two views. .. We've granted the ``group:editors`` :term:`principal` the ``edit`` .. permission in the :term:`root factory` via its ACL, so only a user who .. is a member of the group named ``group:editors`` will be able to .. invoke the views associated with the ``add_page`` or ``edit_page`` .. routes. これらの ``permission`` 引数を追加すると、 Pyramid はリクエストの時に 有効な ``edit`` パーミッションを所有するユーザだけがこれら 2 つのビューを 起動できるという検証を行うようになります。 :term:`root factory` の中で その ACL によって ``group:editors`` :term:`principal` を ``edit`` パーミッションに与えたので、 ``group:editors`` という名前のグループの メンバーであるユーザだけが ``add_page`` または ``edit_page`` のルートに 関連したビューを起動することができます。 .. Adding the ``login.pt`` Template ``login.pt`` テンプレートを追加する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. Add a ``login.pt`` template to your templates directory. It's .. referred to within the login view we just added to ``views.py``. templates ディレクトリに ``login.pt`` テンプレートを追加してください。 それはたった今 ``views.py`` に加えた login ビュー内で参照されます。 .. literalinclude:: src/authorization/tutorial/templates/login.pt :language: xml .. Add a "Logout" link when logged in ログイン中に "Logout" リンクを追加する ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. We'll also need to change our ``edit.pt`` and ``view.pt`` templates to .. display a "Logout" link if someone is logged in. This link will .. invoke the logout view. さらに、誰かがログインしていれば "Logout" リンクを表示するように ``edit.pt`` と ``view.pt`` テンプレートを変更する必要があります。 このリンクは logout ビューを起動するでしょう。 .. To do so we'll add this to both templates within the ``