Révision ebf37dd5
Ajouté par dlaniel il y a plus de 17 ans
- ID ebf37dd5e5f9c523b1a6fc865e5276a627700b5c
doc/vhost-rp | ||
---|---|---|
7 | 7 |
|
8 | 8 |
PythonOutputFilter larpe-filter OURFILTER |
9 | 9 |
SetOutputFilter proxy-html;OURFILTER |
10 |
# SetOutputFilter proxy-html |
|
10 | 11 |
|
11 | 12 |
<LocationMatch "^/(css|images|js)/.*"> |
12 | 13 |
ProxyPass ! |
13 | 14 |
SCGIHandler off |
14 | 15 |
</LocationMatch> |
15 | 16 |
|
16 |
<Location /eo/> |
|
17 |
ProxyPass http://www.entrouvert.com/ |
|
18 |
ProxyPassReverse http://www.entrouvert.com/ |
|
19 |
# ProxyPassReverse / |
|
20 |
ProxyHTMLURLMap / /eo/ |
|
21 |
</Location> |
|
17 |
# Options +FollowSymlinks |
|
18 |
RewriteEngine on |
|
19 |
# RewriteRule /dot/ecrire/index.php /liberty/dot/logout |
|
20 |
|
|
21 |
# <Location /eo/> |
|
22 |
# ProxyPass http://www.entrouvert.com/ |
|
23 |
# ProxyPassReverse http://www.entrouvert.com/ |
|
24 |
# ProxyHTMLURLMap / /eo/ |
|
25 |
# </Location> |
|
22 | 26 |
|
23 | 27 |
# ProxyPass /linuxfr/ http://linuxfr.org/ |
24 | 28 |
<Location /linuxfr/> |
... | ... | |
36 | 40 |
</Location> |
37 | 41 |
|
38 | 42 |
<Location /dot/> |
39 |
Redirect permanent /dot/ecrire/auth.php http://test.org/dot/login |
|
43 |
Redirect permanent /dot/ecrire/auth.php http://test.org/liberty/dot/login |
|
44 |
RewriteEngine on |
|
45 |
RewriteRule /ecrire/index.php /liberty/dot/logout |
|
46 |
# Redirect permanent /dot/ecrire/index.php?logout=1 http://test.org/liberty/dot/liberty/logout |
|
40 | 47 |
ProxyPass http://localhost/~heretik/dotclear/ |
41 | 48 |
# ProxyPassReverse / |
42 |
# ProxyPassReverse http://localhost/~heretik/dotclear/
|
|
49 |
ProxyPassReverse http://localhost/~heretik/dotclear/ |
|
43 | 50 |
ProxyHTMLURLMap /~heretik/dotclear/ /dot/ |
44 | 51 |
# ProxyHTMLURLMap http://localhost/~heretik/dotclear/ /dot/ |
45 | 52 |
</Location> |
larpe/trunk/TODO | ||
---|---|---|
1 |
- Ajouter les fonctionnalités liberty |
|
2 |
- SSO : |
|
3 |
- Interception de l'url d'authentification du site |
|
4 |
- Redirection vers l'url /login sur le relais inverse |
|
5 |
- Sur l'url /login |
|
6 |
- Si deja authentifié (on a un cookie de session) : c'est bon, on redirige vers l'accueil du site (ou autre) |
|
7 |
- Sinon : faire un SSO |
|
8 |
- Rediriger vers l'idp |
|
9 |
- L'utilisateur s'authentifie |
|
10 |
- L'idp redirige vers le relais inverse |
|
11 |
- Si comptes non fédérés : |
|
12 |
- On affiche une page de d'auth locale |
|
13 |
- On authentifie l'utilisateur sur le relais inverse |
|
14 |
- On envoie la demande d'authentification au site |
|
15 |
- On recoit un cookie de session |
|
16 |
- On redirige vers l'accueil du site (ou autre) |
|
17 |
|
|
18 |
|
|
19 |
- Faire un RP pour dotclear |
|
20 |
- Intercepter les urls /ecrire/auth.php |
|
21 |
/admin/auth.php |
|
22 |
et rediriger vers /login |
|
23 |
- Faire un RP pour spip |
|
24 |
- Faire un RP pour linuxfr |
|
25 |
- Intercepter les redirect |
|
26 |
- Remplacer le code html du formulaire par un bouton "connexion" qui fait un SSO |
|
27 |
|
|
28 |
- Page proposant d'établir la fédération, où l'utilisateur entre identifiant / mot de passe du SP |
|
1 |
- Compléter la conf pour que ce soit vraiment générique (+ multi-sites) |
|
2 |
- Récupére la css de la page d'authentification |
|
3 |
- Texte explicatif + traductions |
|
4 |
- Création de nouveaux comptes + jetons |
|
5 |
- Faire les paquets Debian |
|
29 | 6 |
|
7 |
- Tests |
|
8 |
- Linuxfr |
|
9 |
- Remplacer le code html du formulaire par un bouton "connexion" qui fait un SSO |
|
10 |
- Spip |
|
30 | 11 |
|
31 | 12 |
- Interface d'admin permettant de : |
32 | 13 |
- Lister les vhosts existants |
... | ... | |
41 | 22 |
Fait |
42 | 23 |
==== |
43 | 24 |
|
44 |
- RP par vhost (appli1.example.com, rp de appli1.interne) |
|
45 |
- RP par repertoire (www.example.com/appli1, rp de appl1.interne) |
|
25 |
- Configuration des hôtes virtuels d'Apache 2 |
|
26 |
- RP par vhost (appli1.example.com, rp de appli1.interne) |
|
27 |
- RP par repertoire (www.example.com/appli1, rp de appl1.interne) |
|
28 |
|
|
29 |
- Début de filtre Python branché sur Apache à la suite du filtre de réécriture html (proxy_html) |
|
30 |
|
|
31 |
- Ajouter les fonctionnalités liberty |
|
32 |
- SSO (depuis le sp et depuis l'idp) |
|
33 |
- Fédération |
|
34 |
- SLO (depuis le sp et depuis l'idp) |
|
35 |
- Défédération (depuis l'idp) |
|
36 |
|
|
37 |
- Gestion des cookies et des sessions |
|
38 |
|
|
46 | 39 |
- Interface d'admin permettant de : |
47 | 40 |
- Créer de nouveaux vhosts (écriture du fichier) |
48 |
- Début de filtre Python branché sur Apache à la suite du filtre de réécriture html (proxy_html) |
|
41 |
|
|
42 |
- Tests |
|
43 |
- Dotclear |
larpe/trunk/filter/larpe-filter.py | ||
---|---|---|
1 | 1 |
from mod_python import apache |
2 |
import os |
|
2 | 3 |
import re |
3 | 4 |
|
5 |
app_dir = '/var/lib/larpe' |
|
6 |
|
|
4 | 7 |
def outputfilter(filter): |
5 |
# Only filter html code |
|
6 |
if filter.req.content_type is not None: |
|
7 |
is_html = re.search('text/html', filter.req.content_type) |
|
8 |
if filter.req.content_type is not None and not is_html: |
|
9 |
filter.pass_on() |
|
10 |
else: |
|
11 |
if not hasattr(filter.req, 'temp_doc'): # the start |
|
12 |
filter.req.temp_doc = [] # create new attribute to hold document |
|
13 |
# If content-length ended up wrong, Gecko browsers truncated data, so |
|
14 |
if "Content-Length" in filter.req.headers_out: |
|
15 |
del filter.req.headers_out["Content-Length"] |
|
8 |
# Only filter html code |
|
9 |
if filter.req.content_type is not None: |
|
10 |
is_html = re.search('text/html', filter.req.content_type) |
|
11 |
if filter.req.content_type is not None and not is_html: |
|
12 |
filter.pass_on() |
|
13 |
else: |
|
14 |
if not hasattr(filter.req, 'temp_doc'): # the start |
|
15 |
filter.req.temp_doc = [] # create new attribute to hold document |
|
16 |
# If content-length ended up wrong, Gecko browsers truncated data, so |
|
17 |
if 'Content-Length' in filter.req.headers_out: |
|
18 |
del filter.req.headers_out['Content-Length'] |
|
19 |
|
|
20 |
# filter.write(filter.req.headers_in['Cookie']) |
|
21 |
# delete_cookies(filter) |
|
22 |
#filter.req.headers_out['Set-Cookie'] = 'dc_admin="deleted"; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT; path=/' |
|
23 |
|
|
24 |
temp_doc = filter.req.temp_doc |
|
25 |
s = filter.read() |
|
26 |
while s: # could get '' at any point, but only get None at end |
|
27 |
temp_doc.append(s) |
|
28 |
s = filter.read() |
|
29 |
|
|
30 |
if s is None: # the end |
|
31 |
temp_doc = ''.join(temp_doc) |
|
32 |
#filter.req.set_content_length(len(temp_doc)) # this didn't seem to work |
|
33 |
filter.write(temp_doc) |
|
34 |
#filter.write(filter.req.uri) |
|
35 |
filter.close() |
|
16 | 36 |
|
17 |
temp_doc = filter.req.temp_doc |
|
18 |
s = filter.read() |
|
19 |
while s: # could get '' at any point, but only get None at end |
|
20 |
temp_doc.append(s) |
|
21 |
s = filter.read() |
|
37 |
def get_abs_path(s): |
|
38 |
if not s: |
|
39 |
return s |
|
40 |
if s[0] == '/': |
|
41 |
return s |
|
42 |
return os.path.join(app_dir, s) |
|
43 |
|
|
44 |
def get_proxied_site_path(filter): |
|
45 |
proxy_domain_name = filter.req.hostname |
|
46 |
proxied_site_dir = get_proxied_site_name(filter) |
|
47 |
return get_abs_path(os.path.join('sp', proxy_domain_name, proxied_site_dir)) |
|
22 | 48 |
|
23 |
if s is None: # the end |
|
24 |
temp_doc = ''.join(temp_doc) |
|
25 |
#filter.req.set_content_length(len(temp_doc)) # this didn't seem to work |
|
26 |
filter.write(temp_doc) |
|
27 |
#filter.write(filter.req.uri) |
|
28 |
filter.close() |
|
49 |
def get_proxied_site_name(filter): |
|
50 |
uri_tokens = filter.req.uri.split('/') |
|
51 |
if uri_tokens[1] != 'liberty': |
|
52 |
return uri_tokens[1] |
|
53 |
return uri_tokens[2] |
|
54 |
|
|
55 |
def delete_cookies(filter): |
|
56 |
success = False |
|
57 |
cookies_file_name = get_abs_path(os.path.join(get_proxied_site_path(filter), 'cookies_to_delete')) |
|
58 |
cookies_file = open(cookies_file_name, 'r') |
|
59 |
for cookie in cookies_file.read().split(): |
|
60 |
if filter.req.headers_in.has_key('Cookie'): |
|
61 |
cookies_header = filter.req.headers_in['Cookie'] |
|
62 |
# filter.req.temp_doc.append(filter.req.headers_in['Cookie']) |
|
63 |
#filter.req.temp_doc.append(cookie[len(cookie) -1:]) |
|
64 |
cookies_match = re.findall(cookie[:len(cookie) -1], cookies_header) |
|
65 |
if len(cookies_match) > 0: |
|
66 |
filter.req.temp_doc.append('User-Agent') |
|
67 |
# filter.req.temp_doc.append('%s="deleted"; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT; path=/' % cookie.split('=')[0]) |
|
68 |
filter.req.headers_out['Set-Cookie'] = '%s="deleted"; max-age=0; expires=Thu, 01-Jan-1970 00:00:00 GMT; path=/' % cookie.split('=')[0] |
|
69 |
# cookies_file.close() |
|
70 |
# cookies_file = open(cookies_file_name, 'w') |
|
71 |
break |
|
72 |
# else: |
|
73 |
# filter.req.temp_doc.append('dommage') |
|
74 |
cookies_file.close() |
|
75 |
# if success: |
|
76 |
# cookies_file = open(cookies_file_name, 'w') |
|
77 |
# cookies_file.close() |
larpe/trunk/larpe/liberty.ptl | ||
---|---|---|
24 | 24 |
"singleLogout", "singleLogoutReturn", |
25 | 25 |
"federationTermination", "federationTerminationReturn", |
26 | 26 |
('metadata.xml', 'metadata'), 'public_key', |
27 |
'local_auth', 'local_auth_check'] |
|
27 |
'local_auth', 'local_auth_check', 'local_logout']
|
|
28 | 28 |
|
29 | 29 |
def perform_login(self, idp = None): |
30 | 30 |
server = misc.get_lasso_server() |
... | ... | |
190 | 190 |
def local_logout(self): |
191 | 191 |
get_response().expire_cookie('dc_admin', path='/') |
192 | 192 |
get_response().expire_cookie('dc_xd', path='/') |
193 |
#misc.get_html_page('http://localhost/~heretik/dotclear/ecrire/index.php?logout=1') |
|
194 |
# host = 'localhost' |
|
195 |
# query = '/~heretik/dotclear/ecrire/index.php?logout=1' |
|
196 |
# conn = httplib.HTTPConnection(host) |
|
197 |
# conn.request('GET', query, headers = { 'Cookie': 'dc_xd=cbec5e7951856e94d3878c68df6e575a; dc_admin=a%3A3%3A%7Bs%3A7%3A%22user_id%22%3Bs%3A7%3A%22heretik%22%3Bs%3A8%3A%22user_pwd%22%3Bs%3A32%3A%#22cc414bfc9c00475b59c87595299ff31d%22%3Bs%3A8%3A%22remember%22%3Bb%3A0%3B%7D', 'Referer': 'http://localhost/~heretik/dotclear/ecrire/', }) |
|
198 |
# response = conn.getresponse() |
|
199 |
# conn.close() |
|
200 |
|
|
193 | 201 |
|
194 | 202 |
def singleLogoutReturn(self): |
195 | 203 |
returnUrl = '/' + misc.get_proxied_site_name() + '/' |
... | ... | |
214 | 222 |
# Single Logout initiated by IdP |
215 | 223 |
if session.lasso_session_dump: |
216 | 224 |
logout.setSessionFromDump(session.lasso_session_dump) |
217 |
user = get_request().user |
|
225 |
#user = get_request().user |
|
226 |
user = get_session().get_user() |
|
218 | 227 |
if user and user.lasso_dump: |
219 | 228 |
logout.setIdentityFromDump(user.lasso_dump) |
220 | 229 |
if logout.nameIdentifier.content != session.name_identifier: |
... | ... | |
305 | 314 |
return self.fedterm(defederation, session) |
306 | 315 |
|
307 | 316 |
def defederate(self, idp = None): |
308 |
self.local_logout() |
|
309 |
|
|
310 | 317 |
session = get_session() |
311 | 318 |
user = session.get_user() |
312 | 319 |
|
313 |
user_dir = misc.get_abs_path(os.path.join(misc.get_proxied_site_path(), 'users')) |
|
314 |
federation_file_name = os.path.join(user_dir, user.name_identifiers[0]) |
|
315 |
if os.path.isfile(federation_file_name): |
|
316 |
os.remove(federation_file_name) |
|
320 |
self.local_defederate(session) |
|
317 | 321 |
|
318 | 322 |
defederation = lasso.Defederation(misc.get_lasso_server()) |
319 | 323 |
defederation.setSessionFromDump(session.lasso_session_dump) |
... | ... | |
331 | 335 |
rootUrl = '/' + misc.get_proxied_site_name() + '/' |
332 | 336 |
return redirect(rootUrl) |
333 | 337 |
|
338 |
def local_defederate(self, session): |
|
339 |
user = session.get_user() |
|
340 |
self.local_logout() |
|
341 |
if user is not None: |
|
342 |
user_dir = misc.get_abs_path(os.path.join(misc.get_proxied_site_path(), 'users')) |
|
343 |
federation_file_name = os.path.join(user_dir, user.name_identifiers[0]) |
|
344 |
if os.path.isfile(federation_file_name): |
|
345 |
os.remove(federation_file_name) |
|
346 |
|
|
347 |
# if hasattr(session, 'auth_cookie'): |
|
348 |
# cookies_file_name = misc.get_abs_path(os.path.join(misc.get_proxied_site_path(), 'cookies_to_delete')) |
|
349 |
# cookies_file = open(cookies_file_name, 'a') |
|
350 |
# cookies_file.write(session.auth_cookie + '\n') |
|
351 |
# cookies_file.close() |
|
352 |
|
|
353 |
|
|
334 | 354 |
def federationTermination(self): |
335 | 355 |
request = get_request() |
336 | 356 |
if not lasso.isLibertyQuery(request.get_query()): |
... | ... | |
342 | 362 |
return self.fedterm(defederation, session) |
343 | 363 |
|
344 | 364 |
def fedterm(self, defederation, session): |
365 |
self.local_defederate(session) |
|
345 | 366 |
defederation.setSessionFromDump(session.lasso_session_dump) |
346 | 367 |
|
347 |
user = get_request().user |
|
368 |
#user = get_request().user |
|
369 |
user = get_session().get_user() |
|
348 | 370 |
if user and user.lasso_dump: |
349 | 371 |
defederation.setIdentityFromDump(user.lasso_dump) |
350 | 372 |
|
... | ... | |
408 | 430 |
self.federate(user_id, user_password) |
409 | 431 |
return redirect('/' + get_request().get_path().split('/')[2] + '/') |
410 | 432 |
else: |
411 |
return local_auth() |
|
433 |
return self.local_auth()
|
|
412 | 434 |
|
413 | 435 |
def local_auth_check_post (self, user_id, user_password): |
414 | 436 |
url = misc.cfg['auth_url'] |
... | ... | |
421 | 443 |
body = 'user_id=%s&user_pwd=%s' % (user_id, user_password) |
422 | 444 |
conn.request("POST", query, body, {'Content-Type': 'application/x-www-form-urlencoded'}) |
423 | 445 |
response = conn.getresponse() |
446 |
conn.close() |
|
424 | 447 |
cookies = response.getheader('Set-Cookie', None) |
425 |
cookie = re.findall('dc_admin=([^;]+)', cookies)[0]
|
|
426 |
if cookie is not None:
|
|
448 |
cookies_match = re.findall('dc_admin=([^;]+)', cookies)
|
|
449 |
if len(cookies_match) > 0:
|
|
427 | 450 |
# Can't use get_response().set_cookie('dc_admin', cookie, path='/') from quixote because |
428 | 451 |
# it adds double quotes |
429 |
get_response().set_header('Set-Cookie', 'dc_admin=%s; path=/' % cookie) |
|
430 |
conn.close() |
|
452 |
set_cookie = 'dc_admin=%s; path=/' % cookies_match[0] |
|
453 |
get_response().set_header('Set-Cookie', set_cookie) |
|
454 |
# get_session().auth_cookie = set_cookie |
|
431 | 455 |
return response.status |
432 | 456 |
|
433 | 457 |
def local_auth_check_form [html] (self): |
... | ... | |
464 | 488 |
federation_file.close() |
465 | 489 |
|
466 | 490 |
def sso_local_login(self, name_id): |
467 |
proxied_site_dir = get_request().get_path().split('/')[2] |
|
491 |
#proxied_site_dir = get_request().get_path().split('/')[2]
|
|
468 | 492 |
user_dir = misc.get_abs_path(os.path.join(misc.get_proxied_site_path(), 'users')) |
469 | 493 |
federation_file_name = os.path.join(user_dir, name_id) |
470 | 494 |
federation_file = open(federation_file_name, 'r') |
larpe/trunk/larpe/liberty_site.ptl | ||
---|---|---|
17 | 17 |
|
18 | 18 |
class LibertySite(Directory): |
19 | 19 |
|
20 |
_q_exports = ["", "login", "logout", "defederate", "liberty"]
|
|
20 |
_q_exports = ["", "login", "logout", "liberty"] |
|
21 | 21 |
|
22 | 22 |
liberty = liberty.Liberty() |
23 | 23 |
|
... | ... | |
31 | 31 |
logger.info('login') |
32 | 32 |
idps = misc.cfg.get('idp', {}) |
33 | 33 |
|
34 |
if len(idps) == 0: |
|
35 |
return template.error_page(_('SSO support is not yet configured'))
|
|
34 |
# if len(idps) == 0:
|
|
35 |
return template.error_page(_('SSO support is not yet configured')) |
|
36 | 36 |
|
37 | 37 |
if len(idps) == 1 or len([x for x in idps.values() if not x.get('hide', False)]) == 1: |
38 | 38 |
# if there is only one visible IdP, perform login automatically on |
larpe/trunk/larpe/root.ptl | ||
---|---|---|
144 | 144 |
return redirect('.') |
145 | 145 |
|
146 | 146 |
|
147 |
# def _q_traverse(self, path):
|
|
148 |
# session = get_session()
|
|
149 |
# if session:
|
|
150 |
# get_request().user = session.get_user()
|
|
151 |
# else:
|
|
152 |
# get_request().user = None
|
|
147 |
def _q_traverse(self, path): |
|
148 |
session = get_session() |
|
149 |
if session: |
|
150 |
get_request().user = session.get_user() |
|
151 |
else: |
|
152 |
get_request().user = None |
|
153 | 153 |
|
154 |
# response = get_response()
|
|
155 |
# response.filter = {}
|
|
156 |
# if not hasattr(response, 'breadcrumb'):
|
|
157 |
# response.breadcrumb = [ ('', _('Home')) ]
|
|
154 |
response = get_response() |
|
155 |
response.filter = {} |
|
156 |
if not hasattr(response, 'breadcrumb'): |
|
157 |
response.breadcrumb = [ ('', _('Home')) ] |
|
158 | 158 |
|
159 |
# try:
|
|
160 |
# return Directory._q_traverse(self, path)
|
|
161 |
# except errors.TraversalError:
|
|
162 |
# pass
|
|
159 |
try: |
|
160 |
return Directory._q_traverse(self, path) |
|
161 |
except errors.TraversalError: |
|
162 |
pass |
|
163 | 163 |
|
164 | 164 |
# return self._q_index() |
165 |
# return forms.root.RootDirectory()._q_traverse(path)
|
|
165 |
return forms.root.RootDirectory()._q_traverse(path) |
|
166 | 166 |
|
167 | 167 |
def _q_lookup(self, component): |
168 | 168 |
# return SiteUI(component) |
larpe/trunk/notes | ||
---|---|---|
18 | 18 |
- On enregistre temporairement l'identifiant |
19 | 19 |
- On regarde si l'authentification a réussi (cookie ? url ou le site renvoie ?) |
20 | 20 |
- Si oui, on fédère les comptes |
21 |
|
|
22 |
Variante : |
|
23 |
|
|
24 |
- Interception de l'url d'authentification du site |
|
25 |
- Redirection vers l'url /login sur le relais inverse |
|
26 |
- Sur l'url /login |
|
27 |
- Si deja authentifié (on a un cookie de session) : c'est bon, on redirige vers l'accueil du site (ou autre) |
|
28 |
- Sinon : faire un SSO |
|
29 |
- Rediriger vers l'idp |
|
30 |
- L'utilisateur s'authentifie |
|
31 |
- L'idp redirige vers le relais inverse |
|
32 |
- Si comptes non fédérés : |
|
33 |
- On affiche une page de d'auth locale |
|
34 |
- On authentifie l'utilisateur sur le relais inverse |
|
35 |
- On envoie la demande d'authentification au site |
|
36 |
- On recoit un cookie de session |
|
37 |
- On redirige vers l'accueil du site (ou autre) |
|
38 |
|
|
39 |
Gestion des cookies |
|
40 |
------------------- |
|
41 |
|
|
42 |
- On associe à un name_identifier les cookies courants |
|
43 |
- Lors de la défédération, on lie les cookies de l'utilisateur défédéré, et on crée ajoute dans le fichier "cookies_to_delete" une ligne : |
|
44 |
cookie=valeur |
|
45 |
- Dans le filtre python d'apache, on lit ce fichier et pour chaque ligne, on recherche cette chaine dans l'entete "Cookie" |
|
46 |
- Si on la trouve, on ajoute aux entetes en sortie " Set-Cookie: cookie="deleted" " et on supprime cette ligne du fichier |
Formats disponibles : Unified diff
slo + defederate from idp
git-svn-id: svn+ssh://labs.libre-entreprise.org/svnroot/larpe@16 3ed937ae-f919-0410-9a43-8e6f19e4ba6e