46 return self._request.response.status_int |
61 return self._request.response.status_int |
47 |
62 |
48 status_out = property(_get_status_out, _set_status_out) |
63 status_out = property(_get_status_out, _set_status_out) |
49 |
64 |
50 |
65 |
|
66 class PyramidSessionHandler(object): |
|
67 """A CW Session handler that rely on the pyramid API to fetch the needed |
|
68 informations""" |
|
69 |
|
70 def __init__(self, appli): |
|
71 self.appli = appli |
|
72 |
|
73 def get_session(self, req): |
|
74 return req._request.cw_session |
|
75 |
|
76 def logout(self, req, goto_url): |
|
77 del req._request.session['cubicweb.sessionid'] |
|
78 if not req.session.closed: |
|
79 req.session.repo.close(req.session.sessionid) |
|
80 for name, value in security.forget(req._request): |
|
81 req.headers_out.setHeader(name, value) |
|
82 raise cubicweb.web.LogOut(url=goto_url) |
|
83 |
|
84 |
|
85 def render_view(request, vid, **kwargs): |
|
86 vreg = request.registry['cubicweb.registry'] |
|
87 # XXX The select() function could, know how to handle a pyramid |
|
88 # request, and feed it directly to the views that supports it. |
|
89 # On the other hand, we could refine the View concept and decide it works |
|
90 # with a cnx, and never with a WebRequest |
|
91 |
|
92 view = vreg['views'].select(vid, request.cw_request(), **kwargs) |
|
93 |
|
94 view.set_stream() |
|
95 view.render() |
|
96 return view._stream.getvalue() |
|
97 |
|
98 |
|
99 def login(request): |
|
100 repo = request.registry['cubicweb.repository'] |
|
101 |
|
102 response = request.response |
|
103 userid = None |
|
104 |
|
105 if '__login' in request.params: |
|
106 login = request.params['__login'] |
|
107 password = request.params['__password'] |
|
108 |
|
109 try: |
|
110 sessionid = repo.connect(login, password=password) |
|
111 request.session['cubicweb.sessionid'] = sessionid |
|
112 session = repo._sessions[sessionid] |
|
113 userid = session.user.eid |
|
114 except cubicweb.AuthenticationError: |
|
115 raise |
|
116 |
|
117 if userid is not None: |
|
118 headers = security.remember(request, userid) |
|
119 |
|
120 if 'postlogin_path' in request.params: |
|
121 raise HTTPSeeOther( |
|
122 request.params['postlogin_path'], |
|
123 headers=headers) |
|
124 |
|
125 response.headerlist.extend(headers) |
|
126 |
|
127 response.text = render_view(request, 'login') |
|
128 return response |
|
129 |
|
130 |
51 class CubicWebPyramidHandler(object): |
131 class CubicWebPyramidHandler(object): |
52 def __init__(self, appli): |
132 def __init__(self, appli): |
53 self.appli = appli |
133 self.appli = appli |
54 |
134 |
55 def __call__(self, request): |
135 def __call__(self, request): |
56 req = CubicWebPyramidRequest(request) |
136 req = request.cw_request() |
57 request.response.body = self.appli.handle_request(req, req.path) |
137 result = self.appli.handle_request(req, req.path) |
|
138 if result is not None: |
|
139 request.response.body = result |
58 request.response.headers.clear() |
140 request.response.headers.clear() |
59 for k, v in req.headers_out.getAllRawHeaders(): |
141 for k, v in req.headers_out.getAllRawHeaders(): |
60 for item in v: |
142 for item in v: |
61 request.response.headers.add(k, item) |
143 request.response.headers.add(k, item) |
62 return request.response |
144 return request.response |
63 |
145 |
64 |
146 |
|
147 def _cw_cnx(request): |
|
148 # XXX We should not need to use the session. A temporary one should be |
|
149 # enough. (by using repoapi.connect()) |
|
150 cnx = repoapi.ClientConnection(request.cw_session) |
|
151 |
|
152 def cleanup(request): |
|
153 if request.exception is not None: |
|
154 cnx.rollback() |
|
155 else: |
|
156 cnx.commit() |
|
157 cnx.__exit__(None, None, None) |
|
158 |
|
159 request.add_finished_callback(cleanup) |
|
160 cnx.__enter__() |
|
161 return cnx |
|
162 |
|
163 |
|
164 def _cw_session(request): |
|
165 repo = request.registry['cubicweb.repository'] |
|
166 config = request.registry['cubicweb.config'] |
|
167 |
|
168 sessionid = request.session.get('cubicweb.sessionid') |
|
169 |
|
170 if sessionid not in repo._sessions: |
|
171 if not request.authenticated_userid: |
|
172 login, password = config.anonymous_user() |
|
173 sessionid = repo.connect(login, password=password) |
|
174 request.session['cubicweb.sessionid'] = sessionid |
|
175 else: |
|
176 sessionid = request.session.get('cubicweb.sessionid') |
|
177 |
|
178 return repo._sessions[sessionid] |
|
179 |
|
180 |
|
181 def _cw_request(request): |
|
182 return weakref.ref(CubicWebPyramidRequest(request)) |
|
183 |
|
184 |
|
185 def get_principals(userid, request): |
|
186 repo = request.registry['cubicweb.repository'] |
|
187 |
|
188 sessionid = request.session.get('cubicweb.sessionid') |
|
189 |
|
190 if sessionid is None or sessionid not in repo._sessions: |
|
191 try: |
|
192 sessionid = repo.connect( |
|
193 str(userid), __pyramid_directauth=authplugin.EXT_TOKEN) |
|
194 except: |
|
195 log.exception("Failed") |
|
196 raise |
|
197 request.session['cubicweb.sessionid'] = sessionid |
|
198 |
|
199 #session = repo._session[sessionid] |
|
200 |
|
201 with repo.internal_cnx() as cnx: |
|
202 groupnames = [r[1] for r in cnx.execute( |
|
203 'Any X, N WHERE X is CWGroup, X name N, ' |
|
204 'U in_group X, U eid %(userid)s', |
|
205 {'userid': userid})] |
|
206 |
|
207 return groupnames |
|
208 |
|
209 |
|
210 from pyramid.authentication import SessionAuthenticationPolicy |
|
211 from pyramid.authorization import ACLAuthorizationPolicy |
|
212 from pyramid.session import SignedCookieSessionFactory |
|
213 |
|
214 |
|
215 def hello_world(request): |
|
216 request.response.text = \ |
|
217 u"<html><body>Hello %s</body></html>" % request.cw_cnx.user.login |
|
218 return request.response |
|
219 |
|
220 |
65 def includeme(config): |
221 def includeme(config): |
66 appid = config.registry.settings['cubicweb.instance'] |
222 appid = config.registry.settings['cubicweb.instance'] |
67 cwconfig = CubicWebConfiguration.config_for(appid) |
223 cwconfig = CubicWebConfiguration.config_for(appid) |
68 |
224 |
69 cwappli = CubicWebPublisher(cwconfig.repository(), cwconfig) |
225 config.set_session_factory( |
|
226 SignedCookieSessionFactory( |
|
227 secret=config.registry.settings['session.secret'] |
|
228 )) |
|
229 |
|
230 config.set_authentication_policy( |
|
231 SessionAuthenticationPolicy(callback=get_principals)) |
|
232 config.set_authorization_policy(ACLAuthorizationPolicy()) |
|
233 |
|
234 config.registry['cubicweb.config'] = cwconfig |
|
235 config.registry['cubicweb.repository'] = repo = cwconfig.repository() |
|
236 config.registry['cubicweb.registry'] = repo.vreg |
|
237 |
|
238 repo.system_source.add_authentifier(authplugin.DirectAuthentifier()) |
|
239 |
|
240 config.add_request_method( |
|
241 _cw_session, name='cw_session', property=True, reify=True) |
|
242 config.add_request_method( |
|
243 _cw_cnx, name='cw_cnx', property=True, reify=True) |
|
244 config.add_request_method( |
|
245 _cw_request, name='cw_request', property=True, reify=True) |
|
246 |
|
247 config.add_route('login', '/login') |
|
248 config.add_view(login, route_name='login') |
|
249 |
|
250 config.add_route('hello', '/hello') |
|
251 config.add_view(hello_world, route_name='hello') |
|
252 |
|
253 # Set up a defaut route to handle non-catched urls. |
|
254 # This is to keep legacy compatibility for cubes that makes use of the |
|
255 # cubicweb controllers. |
|
256 cwappli = CubicWebPublisher( |
|
257 cwconfig.repository(), cwconfig, |
|
258 session_handler_fact=PyramidSessionHandler) |
70 handler = CubicWebPyramidHandler(cwappli) |
259 handler = CubicWebPyramidHandler(cwappli) |
71 |
260 |
72 config.registry['cubicweb.appli'] = cwappli |
261 config.registry['cubicweb.appli'] = cwappli |
73 config.registry['cubicweb.handler'] = handler |
262 config.registry['cubicweb.handler'] = handler |
74 |
263 |