You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2012/12/07 23:26:35 UTC
[9/49] git commit: [#5240] ticket:213 security functions optimization
[#5240] ticket:213 security functions optimization
* query ProjectRoles using pymongo instead of Ming ODM inside Credentials and RoleCache
* fix stuff that are using Credentials and RoleCache
* new logic for cache invalidation after project creation
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/be14410c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/be14410c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/be14410c
Branch: refs/heads/db/4803
Commit: be14410ceaeb1b84bd3d015f7d4ebb71193b088f
Parents: 1cb7c1d
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Nov 22 15:02:45 2012 +0000
Committer: Tim Van Steenburgh <tv...@gmail.com>
Committed: Wed Dec 5 22:36:20 2012 +0000
----------------------------------------------------------------------
Allura/allura/lib/app_globals.py | 2 +-
Allura/allura/lib/plugin.py | 2 +-
Allura/allura/lib/security.py | 79 ++++++++-------
Allura/allura/model/project.py | 12 ++-
Allura/allura/tests/model/test_auth.py | 7 +-
.../forgetracker/tests/unit/test_ticket_model.py | 1 +
6 files changed, 59 insertions(+), 44 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be14410c/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index a263177..ac46d90 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -228,7 +228,7 @@ class Globals(object):
cred = Credentials.get()
if cred is not None:
for pr in cred.user_roles(user._id, project._id).reaching_roles:
- if pr.name and pr.name[0] != '*':
+ if pr.get('name') and pr.get('name')[0] != '*':
context['is_project_member'] = True
if app:
context.update(
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be14410c/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index f18ee99..6067e27 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -529,7 +529,7 @@ class ProjectRegistrationProvider(object):
# clear the RoleCache for the user so this project will
# be picked up by user.my_projects()
- g.credentials.clear_user(user._id)
+ g.credentials.clear_user(user._id, '*')
with h.push_config(c, project=p, user=user):
ThreadLocalORMSession.flush_all()
# have to add user to context, since this may occur inside auth code
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be14410c/Allura/allura/lib/security.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/security.py b/Allura/allura/lib/security.py
index 0d48fbf..a7cc8bf 100644
--- a/Allura/allura/lib/security.py
+++ b/Allura/allura/lib/security.py
@@ -21,6 +21,12 @@ class Credentials(object):
def __init__(self):
self.clear()
+ @property
+ def project_role(self):
+ from allura import model as M
+ db = M.session.main_doc_session.db
+ return db[M.ProjectRole.__mongometa__.name]
+
@classmethod
def get(cls):
'get the global Credentials instance'
@@ -33,43 +39,47 @@ class Credentials(object):
self.projects = {}
def clear_user(self, user_id, project_id=None):
- self.users.pop((user_id, project_id), None)
+ if project_id == '*':
+ to_remove = [(uid, pid) for uid, pid in self.users if uid == user_id]
+ else:
+ to_remove = [(user_id, project_id)]
+ for uid, pid in to_remove:
+ self.projects.pop(pid, None)
+ self.users.pop((uid, pid), None)
def load_user_roles(self, user_id, *project_ids):
'''Load the credentials with all user roles for a set of projects'''
- from allura import model as M
# Don't reload roles
project_ids = [ pid for pid in project_ids if self.users.get((user_id, pid)) is None ]
- if not project_ids: return
+ if not project_ids: return
if user_id is None:
- q = M.ProjectRole.query.find(
- dict(
- project_id={'$in': project_ids},
- name='*anonymous'))
+ q = self.project_role.find({
+ 'project_id': {'$in': project_ids},
+ 'name': '*anonymous'})
else:
- q0 = M.ProjectRole.query.find(
- dict(project_id={'$in': list(project_ids)},
- name={'$in':['*anonymous', '*authenticated']}))
- q1 = M.ProjectRole.query.find(
- dict(project_id={'$in': list(project_ids)},user_id=user_id))
+ q0 = self.project_role.find({
+ 'project_id': {'$in': project_ids},
+ 'name': {'$in': ['*anonymous', '*authenticated']}})
+ q1 = self.project_role.find({
+ 'project_id': {'$in': project_ids},
+ 'user_id': user_id})
q = chain(q0, q1)
roles_by_project = dict((pid, []) for pid in project_ids)
for role in q:
- roles_by_project[role.project_id].append(role)
+ roles_by_project[role['project_id']].append(role)
for pid, roles in roles_by_project.iteritems():
self.users[user_id, pid] = RoleCache(self, roles)
def load_project_roles(self, *project_ids):
'''Load the credentials with all user roles for a set of projects'''
- from allura import model as M
# Don't reload roles
project_ids = [ pid for pid in project_ids if self.projects.get(pid) is None ]
- if not project_ids: return
- q = M.ProjectRole.query.find(dict(
- project_id={'$in': project_ids}))
+ if not project_ids: return
+ q = self.project_role.find({
+ 'project_id': {'$in': project_ids}})
roles_by_project = dict((pid, []) for pid in project_ids)
for role in q:
- roles_by_project[role.project_id].append(role)
+ roles_by_project[role['project_id']].append(role)
for pid, roles in roles_by_project.iteritems():
self.projects[pid] = RoleCache(self, roles)
@@ -87,14 +97,13 @@ class Credentials(object):
'''
:returns: a RoleCache of ProjectRoles for given user_id and project_id, *anonymous and *authenticated checked as appropriate
'''
- from allura import model as M
roles = self.users.get((user_id, project_id))
if roles is None:
if project_id is None:
if user_id is None:
q = []
else:
- q = M.ProjectRole.query.find(dict(user_id=user_id))
+ q = self.project_role.find({'user_id': user_id})
roles = RoleCache(self, q)
else:
self.load_user_roles(user_id, project_id)
@@ -126,7 +135,7 @@ class RoleCache(object):
def _iter():
for r in self:
for k,v in tests:
- val = getattr(r, k)
+ val = r.get(k)
if callable(v):
if not v(val): break
elif v != val: break
@@ -146,19 +155,19 @@ class RoleCache(object):
@LazyProperty
def index(self):
- return dict((r._id, r) for r in self.q)
+ return dict((r['_id'], r) for r in self.q)
@LazyProperty
def named(self):
return RoleCache(self.cred, (
r for r in self
- if r.name and not r.name.startswith('*')))
+ if r.get('name') and not r.get('name').startswith('*')))
@LazyProperty
def reverse_index(self):
rev_index = defaultdict(list)
for r in self:
- for rr_id in r.roles:
+ for rr_id in r['roles']:
rev_index[rr_id].append(r)
return rev_index
@@ -169,22 +178,22 @@ class RoleCache(object):
to_visit = list(self)
while to_visit:
r = to_visit.pop(0)
- if r in visited: continue
- visited.add(r)
+ if r['_id'] in visited: continue
+ visited.add(r['_id'])
yield r
- pr_rindex = self.cred.project_roles(r.project_id).reverse_index
- to_visit += pr_rindex[r._id]
+ pr_rindex = self.cred.project_roles(r['project_id']).reverse_index
+ to_visit += pr_rindex[r['_id']]
return RoleCache(self.cred, _iter())
@LazyProperty
def users_that_reach(self):
- return [
- r.user for r in self.roles_that_reach if r.user ]
+ from allura import model as M
+ uids = [uid for uid in self.userids_that_reach if uid]
+ return M.User.query.find({'_id': {'$in': uids}})
@LazyProperty
def userids_that_reach(self):
- return [
- r.user_id for r in self.roles_that_reach ]
+ return [ r['user_id'] for r in self.roles_that_reach ]
@LazyProperty
def reaching_roles(self):
@@ -195,16 +204,16 @@ class RoleCache(object):
(rid, role) = to_visit.pop()
if rid in visited: continue
yield role
- pr_index = self.cred.project_roles(role.project_id).index
+ pr_index = self.cred.project_roles(role['project_id']).index
if rid in pr_index:
- for i in pr_index[rid].roles:
+ for i in pr_index[rid]['roles']:
if i in pr_index:
to_visit.append((i, pr_index[i]))
return RoleCache(self.cred, _iter())
@LazyProperty
def reaching_ids(self):
- return [ r._id for r in self.reaching_roles ]
+ return [ r['_id'] for r in self.reaching_roles ]
@LazyProperty
def reaching_ids_set(self):
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be14410c/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index 7861243..da0f816 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -20,7 +20,7 @@ from allura.lib.security import has_access
from .session import main_orm_session
from .session import project_orm_session, project_doc_session
from .neighborhood import Neighborhood
-from .auth import ProjectRole
+from .auth import ProjectRole, User
from .timeline import ActivityNode, ActivityObject
from .types import ACL, ACE
@@ -458,9 +458,10 @@ class Project(MappedClass, ActivityNode, ActivityObject):
@property
def named_roles(self):
+ roles_ids = [r['_id'] for r in g.credentials.project_roles(self.root_project._id).named]
roles = sorted(
- g.credentials.project_roles(self.root_project._id).named,
- key=lambda r:r.name.lower())
+ ProjectRole.query.find({'_id': {'$in': roles_ids}}),
+ key=lambda r: r.name.lower())
return roles
def install_app(self, ep_name, mount_point=None, mount_label=None, ordinal=None, **override_options):
@@ -598,7 +599,8 @@ class Project(MappedClass, ActivityNode, ActivityObject):
named_roles = security.RoleCache(
g.credentials,
g.credentials.project_roles(project_id=self.root_project._id).named)
- return [ r.user for r in named_roles.roles_that_reach if r.user_id is not None ]
+ uids = [uid for uid in named_roles.userids_that_reach if uid is not None]
+ return list(User.query.find({'_id': {'$in': uids}}))
def users_with_role(self, *role_names):
"""Return all users in this project that have at least one of the roles
@@ -624,7 +626,7 @@ class Project(MappedClass, ActivityNode, ActivityObject):
return None
named_roles = g.credentials.project_roles(project_id=self.root_project._id).named
for r in named_roles.roles_that_reach:
- if r.user_id == u._id: return u
+ if r.get('user_id') == u._id: return u
return None
def configure_project(
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be14410c/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index e32349c..46bdf97 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -97,8 +97,11 @@ def test_project_role():
role = M.ProjectRole(project_id=c.project._id, name='test_role')
c.user.project_role().roles.append(role._id)
ThreadLocalORMSession.flush_all()
- for pr in g.credentials.user_roles(
- c.user._id, project_id=c.project.root_project._id):
+ roles = g.credentials.user_roles(
+ c.user._id, project_id=c.project.root_project._id)
+ roles_ids = [role['_id'] for role in roles]
+ roles = M.ProjectRole.query.find({'_id': {'$in': roles_ids}})
+ for pr in roles:
assert pr.display()
pr.special
assert pr.user in (c.user, None, M.User.anonymous())
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/be14410c/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
index a66ef9a..0bc9e5d 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_ticket_model.py
@@ -75,6 +75,7 @@ class TestTicketModel(TrackerTestWithModel):
role_developer = ProjectRole.by_name('Developer')._id
role_creator = t.reported_by.project_role()._id
developer.project_role().roles.append(role_developer)
+ ThreadLocalORMSession.flush_all()
cred = Credentials.get().clear()
t.private = True