Browse Source

LDAP: upodate user attr with ldap attr

Bastien Sevajol 9 years ago
parent
commit
933609f740

+ 1 - 1
tracim/test.ini View File

@@ -31,7 +31,7 @@ ldap_base_dn = dc=directory,dc=fsf,dc=org
31 31
 ldap_bind_dn = cn=admin,dc=directory,dc=fsf,dc=org
32 32
 ldap_bind_pass = toor
33 33
 ldap_ldap_naming_attribute = uid
34
-ldap_user_attributes = mail=email
34
+ldap_user_attributes = mail=email,pubname=display_name
35 35
 ldap_tls = False
36 36
 ldap_group_enabled = False
37 37
 use = config:development.ini

+ 4 - 2
tracim/tracim/fixtures/ldap.py View File

@@ -40,7 +40,8 @@ ldap_test_server_fixtures = {
40 40
             'attributes': {
41 41
                 'uid': 'richard-not-real-email@fsf.org',
42 42
                 'userPassword': 'rms',
43
-                'mail': 'richard-not-real-email@fsf.org'
43
+                'mail': 'richard-not-real-email@fsf.org',
44
+                'pubname': 'Richard Stallman',
44 45
             }
45 46
         },
46 47
         {
@@ -49,7 +50,8 @@ ldap_test_server_fixtures = {
49 50
             'attributes': {
50 51
                 'uid': 'lawrence-not-real-email@fsf.org',
51 52
                 'userPassword': 'foobarbaz',
52
-                'mail': 'lawrence-not-real-email@fsf.org'
53
+                'mail': 'lawrence-not-real-email@fsf.org',
54
+                'pubname': 'Lawrence Lessig',
53 55
             }
54 56
         },
55 57
     ]

+ 20 - 9
tracim/tracim/lib/auth/ldap.py View File

@@ -1,4 +1,5 @@
1 1
 # -*- coding: utf-8 -*-
2
+import transaction
2 3
 from tg.configuration.auth import TGAuthMetadata
3 4
 from who_ldap import LDAPAttributesPlugin as BaseLDAPAttributesPlugin
4 5
 from who_ldap import LDAPGroupsPlugin as BaseLDAPGroupsPlugin
@@ -92,19 +93,27 @@ class LDAPSearchAuthenticatorPlugin(BaseLDAPSearchAuthenticatorPlugin):
92 93
         # Note: super().authenticate return None if already authenticated or not found
93 94
         email = super().authenticate(environ, identity)
94 95
         if email:
95
-            self._sync_ldap_user(email)
96
+            self._sync_ldap_user(email, environ, identity)
96 97
         return email
97 98
 
98
-    def _sync_ldap_user(self, email):
99
+    def _sync_ldap_user(self, email, environ, identity):
100
+        # Create or get user for connected email
99 101
         if not self._user_api.user_with_email_exists(email):
100 102
             user = User(email=email, imported_from=LDAPAuth.name)
101 103
             DBSession.add(user)
102
-            import transaction
103
-            transaction.commit()
104
+        else:
105
+            user = self._user_api.get_one_by_email(email)
106
+
107
+        # Retrieve ldap user attributes
108
+        self._auth.ldap_user_provider.add_metadata_for_auth(environ, identity)
104 109
 
105
-            # TODO - B.S. - 20160208: Voir avec Damien, si je ne fait pas de transaction.commit()
106
-            # manuellement la donnée n'est pas en base.
107
-            # self._user_api.create_user(email=email, save_now=True)
110
+        # Update user with ldap attributes
111
+        user_ldap_values = identity.get('user').copy()
112
+        for field_name in user_ldap_values:
113
+            setattr(user, field_name, user_ldap_values[field_name])
114
+
115
+        DBSession.flush()
116
+        transaction.commit()
108 117
 
109 118
 
110 119
 class LDAPApplicationAuthMetadata(TGAuthMetadata):
@@ -156,9 +165,11 @@ class LDAPAttributesPlugin(BaseLDAPAttributesPlugin):
156 165
         self._user_api = UserApi(None)
157 166
 
158 167
     def add_metadata(self, environ, identity):
168
+        # We disable metadata recuperation, we do it at connection in LDAPSearchAuthenticatorPlugin._sync_ldap_user
169
+        return
170
+
171
+    def add_metadata_for_auth(self, environ, identity):
159 172
         super().add_metadata(environ, identity)
160
-        # TODO - B.S. - 20160212: identity contains now som information from LDAP what we can save in local database
161
-        identity[self.name] = self._user_api.get_one_by_email(identity.get('repoze.who.userid'))
162 173
 
163 174
     @property
164 175
     def local_fields(self):

+ 18 - 1
tracim/tracim/tests/__init__.py View File

@@ -1,10 +1,12 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 """Unit and functional test suite for tracim."""
3 3
 import argparse
4
+import os
4 5
 from os import getcwd
5 6
 
6 7
 import ldap3
7 8
 import tg
9
+import time
8 10
 import transaction
9 11
 from gearbox.commands.setup_app import SetupAppCommand
10 12
 from ldap_test import LdapServer
@@ -20,7 +22,7 @@ from sqlalchemy.schema import Sequence
20 22
 from sqlalchemy.schema import Table
21 23
 from tg import config
22 24
 from tg.util import Bunch
23
-from webtest import TestApp
25
+from webtest import TestApp as BaseTestApp, AppError
24 26
 from who_ldap import make_connection
25 27
 
26 28
 from tracim.command import BaseCommand
@@ -32,6 +34,21 @@ __all__ = ['setup_app', 'setup_db', 'teardown_db', 'TestController']
32 34
 application_name = 'main_without_authn'
33 35
 
34 36
 
37
+class TestApp(BaseTestApp):
38
+    def _check_status(self, status, res):
39
+        """ Simple override to print html content when error"""
40
+        try:
41
+            super()._check_status(status, res)
42
+        except AppError as exc:
43
+            dump_file_path = "/tmp/debug_%d_%s.html" % (time.time() * 1000, res.request.path_qs[1:])
44
+            if os.path.exists("/tmp"):
45
+                with open(dump_file_path, 'w') as dump_file:
46
+                    print(res.ubody, file=dump_file)
47
+                # Update exception message with info about this dumped file
48
+                exc.args = ('%s html error file dump in %s' % (exc.args[0], dump_file_path), ) + exc.args[1:]
49
+            raise exc
50
+
51
+
35 52
 def load_app(name=application_name):
36 53
     """Load the test application."""
37 54
     return TestApp(loadapp('config:test.ini#%s' % name, relative_to=getcwd()))

+ 14 - 1
tracim/tracim/tests/functional/test_ldap_authentication.py View File

@@ -3,7 +3,7 @@
3 3
 Integration tests for the ldap authentication sub-system.
4 4
 """
5 5
 from tracim.fixtures.ldap import ldap_test_server_fixtures
6
-from nose.tools import eq_
6
+from nose.tools import eq_, ok_
7 7
 
8 8
 from tracim.model import DBSession, User
9 9
 from tracim.tests import LDAPTest, TracimTestController
@@ -39,3 +39,16 @@ class TestAuthentication(LDAPTest, TracimTestController):
39 39
 
40 40
         # User is registered in tracim database
41 41
         eq_(1, DBSession.query(User).filter(User.email == 'richard-not-real-email@fsf.org').count())
42
+
43
+    def test_ldap_attributes_sync(self):
44
+        # User is already know in database
45
+        eq_(1, DBSession.query(User).filter(User.email == 'lawrence-not-real-email@fsf.org').count())
46
+
47
+        # His display name is Lawrence L.
48
+        lawrence = DBSession.query(User).filter(User.email == 'lawrence-not-real-email@fsf.org').one()
49
+        eq_('Lawrence L.', lawrence.display_name)
50
+
51
+        # After connexion with LDAP, his display_name is updated (see ldap fixtures)
52
+        self._connect_user('lawrence-not-real-email@fsf.org', 'foobarbaz')
53
+        lawrence = DBSession.query(User).filter(User.email == 'lawrence-not-real-email@fsf.org').one()
54
+        eq_('Lawrence Lessig', lawrence.display_name)

+ 1 - 1
tracim/tracim/tests/functional/test_ldap_restrictions.py View File

@@ -59,7 +59,7 @@ class TestAuthentication(LDAPTest, TracimTestController):
59 59
 
60 60
         # If we force edit of user, "email" field will be not updated
61 61
         eq_(lawrence.email, 'lawrence-not-real-email@fsf.org')
62
-        eq_(lawrence.display_name, 'Lawrence Lessig')
62
+        eq_(lawrence.display_name, 'Lawrence L.')
63 63
 
64 64
         try_post_user = self.app.post(
65 65
             '/user/%d?_method=PUT' % lawrence.user_id,

+ 1 - 1
tracim/tracim/websetup/bootstrap.py View File

@@ -43,7 +43,7 @@ def bootstrap(command, conf, vars):
43 43
         # TODO: - B.S. - 20160212: Following fixture is LDAP tests specific, should make an little fixture management
44 44
         # for tests
45 45
         lawrence = model.User()
46
-        lawrence.display_name = 'Lawrence Lessig'
46
+        lawrence.display_name = 'Lawrence L.'
47 47
         lawrence.email = 'lawrence-not-real-email@fsf.org'
48 48
         lawrence.password = 'foobarbaz'
49 49
         model.DBSession.add(lawrence)