Pyramidのauthentication policyで気になったこととその実装
groupを使っている時にuseridとgroup名が同じ場合、認可されてしまう気がしたのでちょっと調べたことです。
結論としては、callbackでgroupfinderを叩かない、
もしくは、AuthenticationPolicyは自前で実装するほうが安全だと思います。
誤解していなければ問題はないとは思いますが。。。
問題のコードはこちら(一部略)
pyramid/pyramid/authentication.py at master · Pylons/pyramid · GitHub
class CallbackAuthenticationPolicy(object): """ Abstract class """ (略) def effective_principals(self, request): effective_principals = [Everyone] userid = self.unauthenticated_userid(request) if userid is None: return effective_principals if self._clean_principal(userid) is None: return effective_principals if self.callback is None: groups = [] else: groups = self.callback(userid, request) if groups is None: # is None! return effective_principals effective_principals.append(Authenticated) effective_principals.append(userid) effective_principals.extend(groups) return effective_principals
turtorialではこう書いてある
Adding Authorization — The Pyramid Web Application Development Framework v1.4.5
- security.py
USERS = {'editor':'editor', 'viewer':'viewer'} GROUPS = {'editor':['group:editors']} def groupfinder(userid, request): if userid in USERS: return GROUPS.get(userid, [])
- models.py(wiki class)
class Wiki(PersistentMapping): __name__ = None __parent__ = None __acl__ = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'edit') ]
- __init__.py
def main(global_config, **settings): authn_policy = AuthTktAuthenticationPolicy( 'sosecret', callback=groupfinder, hashalg='sha512') authz_policy = ACLAuthorizationPolicy() config = Configurator(root_factory=root_factory, settings=settings) config.set_authentication_policy(authn_policy) config.set_authorization_policy(authz_policy) config.include('pyramid_chameleon') config.add_static_view('static', 'static', cache_max_age=3600) config.scan() return config.make_wsgi_app()
もしuseridに'group:editors'が入ったら危なくないですか…('A`)
調べたところ
https://groups.google.com/forum/#!topic/pylons-discuss/ObPtBp67f0U
(中略)
Thus it's recommended that you store an integer for the user id, or something that would not conflict accidentally with your ACLs.
user_idをintでしといたほうがいいとなるほど。
でもそういうことあまり書かれてないような…
というかBasicAuthAuthenticationPolicyとかはそうしてないんじゃないっすか…
でもusername, password = auth.split(':', 1)してるからいいのかな…
自分でauthentication policy書くとき
pyramid cookbookにいい感じのテンプレートがあったのでこうするとよさげ
http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/auth/custom.html
class MyAuthenticationPolicy(object): (略) def effective_principals(self, request): principals = [Everyone] user = request.user if user: principals += [Authenticated, 'u:%s' % user.id] principals.extend(('g:%s' % g.name for g in user.groups)) return principals
私の場合の実装
身内で使うものだったのであまりセキュリティ高くなくても良いもので
digestっぽい感じでこのhashの整合性を確かめる風にしてます
policyはこんな感じに
https://github.com/cocu/otodo/blob/master/otodo/security.py
@implementer(IAuthenticationPolicy) class APIAuthenticationPolicy(object): (略) def effective_principals(self, request): effective_principals = [Everyone] username = self.authenticated_userid(request) if username: effective_principals.append('user:{username}'.format(username=username)) effective_principals.append('group:user') return effective_principals
これでたぶん大丈夫かな…