Projet

Général

Profil

« Précédent | Suivant » 

Révision ebf37dd5

Ajouté par dlaniel il y a plus de 17 ans

  • ID ebf37dd5e5f9c523b1a6fc865e5276a627700b5c

slo + defederate from idp

git-svn-id: svn+ssh://labs.libre-entreprise.org/svnroot/larpe@16 3ed937ae-f919-0410-9a43-8e6f19e4ba6e

Voir les différences:

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