1 # -*- coding: iso-8859-1 -*-
3 MoinMoin - FusionForge session cookie authentication
5 @copyright: 2005 MoinMoin:AlexanderSchremmer (Thanks to Spreadshirt)
6 @copyright: 2011 Roland Mas
7 @license: GNU GPL, see COPYING for details.
20 from MoinMoin import user
21 from MoinMoin.auth import _PHPsessionParser, BaseAuth
23 perm_name = "plugin_moinmoin_access"
24 perm_map = { "Admins": 3,
28 class FusionForgeError(Exception):
29 def __init__(self, msg):
30 Exception.__init__(self, msg)
34 return "%s\n" % self.msg
37 class FusionForgeLink():
38 def get_config(self, varname, secname='core'):
39 if secname not in self.cachedconfig:
40 self.cachedconfig[secname] = {}
41 if varname not in self.cachedconfig[secname]:
42 self.cachedconfig[secname][varname] = \
43 subprocess.Popen(["@BINARY_PATH@/forge_get_config",
45 stdout=subprocess.PIPE).communicate()[0].rstrip('\n')
46 return self.cachedconfig[secname][varname]
48 def __init__(self, cookies=['session_ser'], autocreate=True):
49 self.cachedconfig = {}
50 self.database_host = self.get_config('database_host')
51 self.database_name = self.get_config('database_name')
52 self.database_user = self.get_config('database_user')
53 self.database_port = self.get_config('database_port')
54 self.database_password = self.get_config('database_password')
55 if (self.database_host != ''):
56 self._conn = psycopg2.connect(database=self.database_name,
57 user=self.database_user,
58 port=self.database_port,
59 password=self.database_password,
60 host=self.database_host)
62 self._conn = psycopg2.connect(database=self.database_name,
63 user=self.database_user,
64 port=self.database_port,
65 password=self.database_password)
67 # We never want to start transactions, all accesses here are read-only
69 self._conn.set_isolation_level \
70 (psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
71 logging.debug ("FusionForgeLink: __init__ done")
76 class FusionForgeSessionAuth(BaseAuth):
77 """ FusionForge session cookie authentication """
79 name = 'fusionforge_session'
80 logout_possible = False
82 def __init__(self, cookies=['session_ser'], autocreate=True):
83 """ @param cookie: Names of the cookies to parse.
85 BaseAuth.__init__(self)
86 self.cookies = cookies
87 self.autocreate = autocreate
89 self.fflink = FusionForgeLink()
90 self.session_key = self.fflink.get_config('session_key')
92 # List super users (Forge admins)
94 conn = self.fflink._conn
96 cur.execute("""SELECT distinct(u.user_name)
101 WHERE u.user_id = pur.user_id
102 AND pur.role_id = pr.role_id
103 AND pr.role_id = prs.role_id
104 AND prs.section_name='forge_admin'
105 AND prs.perm_val = 1""")
108 self.admins = [r[0] for r in cur]
109 logging.debug ("FusionForgeSessionAuth: admins=%s", (self.admins,))
113 cur.execute("""SELECT g.unix_group_name
114 FROM groups g, group_plugin gp, plugins p
115 WHERE g.group_id = gp.group_id
116 AND gp.plugin_id = p.plugin_id
117 AND p.plugin_name = 'moinmoin'""")
120 self.projects = [r[0] for r in cur]
121 logging.debug ("FusionForgeSessionAuth: projects=%s", (self.projects,))
123 def get_moinmoin_acl_string(self, project_name):
124 conn = self.fflink._conn
127 # Get perm setting for anonymous users
129 query = """SELECT prs.perm_val
130 FROM pfo_role_setting prs, groups
131 WHERE prs.role_id = 1
132 AND prs.section_name = '%s'
133 AND groups.unix_group_name = '%s'
134 AND prs.ref_id = groups.group_id""" \
135 % (perm_name, project_name)
136 val = cur.execute(query)
139 anon_perm = [k for k, v in perm_map.iteritems() if v == val[0]]
141 anon_perm = anon_perm[0]
146 { 'Admins': 'read,write,delete,revert,admin',
147 'Writers': 'read,write,delete,revert',
150 rights = [ 'FFSiteAdminsGroup:read,write,delete,revert,admin' ] \
151 + map (lambda (g, right):
152 'FFProject_%s_%sGroup:%s' % (project_name, g, right),
153 rights_dict.iteritems ())
155 if anon_perm and rights_dict.has_key(anon_perm):
156 rights.append ('All:' + rights_dict[anon_perm])
158 rights.append ('All:')
160 logging.debug ("FusionForgeSessionAuth.get_moinmoin_acl_string: %s",
162 return string.join (rights)
164 def get_permission_entries (self, project_name, perm, user_name = None):
165 conn = self.fflink._conn
169 ucond = "u.user_name = '%s'" % (user_name)
173 # ??? query should also include user if permission is granted to
174 # authenticated non-members.
176 query = """SELECT DISTINCT(u.user_name)
177 FROM users u, pfo_user_role pur, pfo_role pr,
178 pfo_role_setting prs, groups
180 AND ((u.user_id = pur.user_id
181 AND pur.role_id = pr.role_id
182 AND pr.role_id = prs.role_id)
184 AND prs.section_name = '%s'
185 AND groups.unix_group_name = '%s'
186 AND prs.perm_val = %d
187 AND prs.ref_id = groups.group_id""" \
188 % (ucond, perm_name, project_name, perm_map[perm])
189 logging.debug ("get_perm_entries: " + query)
193 result = [u[0] for u in cur]
194 logging.debug (" -> %s " % (result,))
197 def check_permission (self, project_name, perm, user_name):
198 return len(self.get_permission_entries \
199 (project_name, perm, user_name)) > 0
201 def request(self, request, user_obj, **kw):
202 cookies = kw.get('cookie')
203 if cookies is None or cookies == {}:
206 for cookiename in cookies:
207 if cookiename not in self.cookies:
210 urllib.unquote(cookies[cookiename]).decode('iso-8859-1')
212 m = re.search('^([A-Za-z0-9+/=]+)!([A-Za-z0-9+/=]+)$', cookievalue)
215 (sserial, shash) = m.group(1, 2)
217 sdata = base64.b64decode(sserial)
218 shash = base64.b64decode(shash)
219 H = hmac.new(self.session_key, sdata, hashlib.sha256)
220 if H.digest() != shash:
223 m = re.search('(.*)<(.*)<(.*)<(.*)<(.*)', sdata)
226 (time, user_id, ip, nonce, user_agent) = m.group(1, 2, 3, 4, 5)
228 conn = self.fflink._conn
230 cur.execute("""SELECT user_name, realname
231 FROM users WHERE user_id=%s""", [user_id])
232 (loginname, realname) = cur.fetchone()
235 # MoinMoin doesn't enforce unicity of realnames
236 u = user.User(request, name=loginname, auth_username=loginname,
237 auth_method=self.name)
239 if u and self.autocreate:
240 u.create_or_update(True)
244 self.auth_user = None