21: 承認によるリソースの保護(21: Protecting Resources With Authorization)¶
操作行うための必要な権限(パーミッション))を説明するリソースにセキュリティーステートメントを割り当てます。
背景(Background)¶
アプリケーションにはWebブラウザ経由でコンテンツを追加/編集/削除できるURLがあります。アプリケーションにセキュリティを追加する時です。追加/編集ビューを保護するためにログイン(usernameに editor
passwordに editor
)を要求するようにしましょう。他のビューはパスワードなしで引き続き使用できます。
目的(Objectives)¶
- 認証、許可、アクセス許可、およびアクセス制御リスト(ACL)についてのPyramidの概念を紹介します。
- 作成した root factory はアプリケーションのトップにクラスのインスタンスを返します。
- セキュリティステートメントをルートリソースに割り当てます。
- ビューにパーミッションを追加します。
- 適切な権限のないURLへのアクセス処理をするために Forbidden view を提供します。。
手順(Steps)¶
認証の手順を出発点として使用します:
$ cd ..; cp -r authentication authorization; cd authorization $ $VENV/bin/pip install -e .
authorization/tutorial/__init__.py
を変更して、configurator にルートファクトリを指定します:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy from pyramid.config import Configurator from .security import groupfinder def main(global_config, **settings): config = Configurator(settings=settings, root_factory='.resources.Root') config.include('pyramid_chameleon') # Security policies authn_policy = AuthTktAuthenticationPolicy( settings['tutorial.secret'], callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.add_route('home', '/') config.add_route('hello', '/howdy') config.add_route('login', '/login') config.add_route('logout', '/logout') config.scan('.views') return config.make_wsgi_app()
authorization/tutorial/resources.py
に実装する必要があることを意味します:1 2 3 4 5 6 7 8 9
from pyramid.security import Allow, Everyone class Root(object): __acl__ = [(Allow, Everyone, 'view'), (Allow, 'group:editors', 'edit')] def __init__(self, request): pass
authorization/tutorial/views.py
を変更してhello
ビューの編集権限を要求するようにする、禁止ビューを実装します::1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
from pyramid.httpexceptions import HTTPFound from pyramid.security import ( remember, forget, ) from pyramid.view import ( view_config, view_defaults, forbidden_view_config ) from .security import ( USERS, check_password ) @view_defaults(renderer='home.pt') class TutorialViews: def __init__(self, request): self.request = request self.logged_in = request.authenticated_userid @view_config(route_name='home') def home(self): return {'name': 'Home View'} @view_config(route_name='hello', permission='edit') def hello(self): return {'name': 'Hello View'} @view_config(route_name='login', renderer='login.pt') @forbidden_view_config(renderer='login.pt') def login(self): request = self.request login_url = request.route_url('login') referrer = request.url if referrer == login_url: referrer = '/' # never use login form itself as came_from came_from = request.params.get('came_from', referrer) message = '' login = '' password = '' if 'form.submitted' in request.params: login = request.params['login'] password = request.params['password'] hashed_pw = USERS.get(login) if hashed_pw and check_password(password, hashed_pw): headers = remember(request, login) return HTTPFound(location=came_from, headers=headers) message = 'Failed login' return dict( name='Login', message=message, url=request.application_url + '/login', came_from=came_from, login=login, password=password, ) @view_config(route_name='logout') def logout(self): request = self.request headers = forget(request) url = request.route_url('home') return HTTPFound(location=url, headers=headers)
Pyramidアプリケーションを以下のように実行します:
$ $VENV/bin/pserve development.ini --reload
http://localhost:6543/ をブラウザで開きます。
まだログインしているなら 「Log Out」リンクをクリックします。
http://localhost:6543/howdy をブラウザでアクセスするとログインするように求められます。
分析(Analysis)¶
今回のシンプルなチュートリアルのステップは次のように成り立ってます:
- ビューにはパーミッション (
edit
) が必要です - ビュー (the
Root
) のコンテキストにはアクセスコントロールリスト(ACL)があります。 - ACLは``edit`` 権限が``Root`` で
group:editors
プリンシパルに対して利用可能であることを示します。 - 登録された
groupfinder
の回答は、特定のユーザ (editor
) が特定のグループ (group:editors
) を持っているかどうかを示します。
要約すると、hello
には edit
権限が必要です。 Root
は group:editors
の edit
権限を持っています。
もちろんこれは``Root`` にのみ適用されます。 サイトの他の部分(a.k.aコンテキスト)は、異なるACLを有する可能性があります。
ログインしていない場合は /howdy
にアクセスしてログイン画面を表示する必要があります。 Pyramidは使用するログインページをどのように知っていますか? Pyramidではビューに @forbidden_view_config
をデコレートすることによってログインビューを使用するように指示できます。
エクストラクレジット(Extra credit)¶
renderer
に@forbidden_view_config
デコレータを入れる必要がありますか?- おそらく充分な権限(禁止されている)が不足していてもっとリッチになることを望むでしょう。どのように変更できますか?
- おそらくデータベースにセキュリティステートメントを格納してブラウザ経由で編集したいと考えています。これはどうすれば実現しますか?
- 異なる種類のオブジェクトに異なるセキュリティステートメントが必要な場合はどうなりますか?同じ種類のオブジェクトでもURL階層の異なる部分にあるのでしょうか?