You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2014/06/19 17:53:09 UTC

[1/9] git commit: [#7406] add autoregister method for LDAP logins

Repository: allura
Updated Branches:
  refs/heads/master 8f1fed0de -> 899d18286


[#7406] add autoregister method for LDAP logins


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/d84231f6
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/d84231f6
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/d84231f6

Branch: refs/heads/master
Commit: d84231f6e2d30f354945483355e121d829c6489f
Parents: 72b8f8f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Jun 11 21:24:54 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:49 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py                     | 37 +++++++++++++++-----
 .../tests/unit/test_ldap_auth_provider.py       |  5 ++-
 Allura/development.ini                          |  6 ++++
 3 files changed, 39 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d84231f6/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 6a70cdf..2e6000d 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -312,6 +312,15 @@ class LdapAuthenticationProvider(AuthenticationProvider):
     def register_user(self, user_doc):
         from allura import model as M
         result = M.User(**user_doc)
+        if asbool(config.get('auth.ldap.autoregister', True)):
+            if asbool(config.get('auth.allow_user_registration', True)):
+                raise Exception('You should not have both "auth.ldap.autoregister" and '
+                                '"auth.allow_user_registration" set to true')
+            else:
+                log.debug('LdapAuth: autoregister is true, so only creating the mongo record (no creating ldap record)')
+                return result
+
+        # full registration into LDAP
         dn_u = 'uid=%s,%s' % (
             ldap.dn.escape_dn_chars(user_doc['username']),
             config['auth.ldap.suffix'])
@@ -412,26 +421,38 @@ class LdapAuthenticationProvider(AuthenticationProvider):
         if ldap is None:
             raise Exception('The python-ldap package needs to be installed.  Run `pip install python-ldap` in your allura environment.')
         from allura import model as M
-        user = M.User.query.get(
-            username=self.request.params['username'], disabled=False)
-        if user is None:
-            log.debug('LdapAuth: no active user {} found in local mongo, not checking LDAP'.format(self.request.params['username']))
+        username = self.request.params['username']
+        if not self._validate_password(username, self.request.params['password']):
             raise exc.HTTPUnauthorized()
-        if not self.validate_password(user, self.request.params['password']):
+        user = M.User.query.get(username=username)
+        if user is None:
+            if asbool(config.get('auth.ldap.autoregister', True)):
+                log.debug('LdapAuth: authorized user {} needs a mongo record registered.  Creating...'.format(username))
+                user = M.User.register({'username': username})
+            else:
+                log.debug('LdapAuth: no user {} found in local mongo'.format(username))
+                raise exc.HTTPUnauthorized()
+        elif user.disabled:
+            log.debug('LdapAuth: user {} is disabled in Allura'.format(username))
             raise exc.HTTPUnauthorized()
         return user
 
     def validate_password(self, user, password):
+        '''by user'''
+        return self._validate_password(user.username, password)
+
+    def _validate_password(self, username, password):
+        '''by username'''
         try:
             dn = 'uid=%s,%s' % (
-                ldap.dn.escape_dn_chars(user.username),
+                ldap.dn.escape_dn_chars(username),
                 config['auth.ldap.suffix'])
             con = ldap.initialize(config['auth.ldap.server'])
             con.bind_s(dn, password)
             con.unbind_s()
             return True
-        except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM):
-            log.debug('LdapAuth: could not authenticate {}'.format(user.username), exc_info=True)
+        except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM, ldap.NO_SUCH_OBJECT):
+            log.debug('LdapAuth: could not authenticate {}'.format(username), exc_info=True)
         return False
 
     def user_project_shortname(self, user):

http://git-wip-us.apache.org/repos/asf/allura/blob/d84231f6/Allura/allura/tests/unit/test_ldap_auth_provider.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_ldap_auth_provider.py b/Allura/allura/tests/unit/test_ldap_auth_provider.py
index 2887133..e780f59 100644
--- a/Allura/allura/tests/unit/test_ldap_auth_provider.py
+++ b/Allura/allura/tests/unit/test_ldap_auth_provider.py
@@ -21,9 +21,11 @@ from mock import patch, Mock
 from nose.tools import assert_equal, assert_not_equal, assert_true
 from webob import Request
 from ming.orm.ormsession import ThreadLocalORMSession
+from tg import config
 
 from alluratest.controller import setup_basic_test
 from allura.lib import plugin
+from allura.lib import helpers as h
 from allura import model as M
 
 
@@ -85,7 +87,8 @@ class TestLdapAuthenticationProvider(object):
         self.provider._encode_password = Mock(return_value='new-password-hash')
 
         assert_equal(M.User.query.get(username=user_doc['username']), None)
-        self.provider.register_user(user_doc)
+        with h.push_config(config, **{'auth.ldap.autoregister': 'false'}):
+            self.provider.register_user(user_doc)
         ThreadLocalORMSession.flush_all()
         assert_not_equal(M.User.query.get(username=user_doc['username']), None)
 

http://git-wip-us.apache.org/repos/asf/allura/blob/d84231f6/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 0470f67..c091b32 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -85,6 +85,12 @@ auth.ldap.schroot_name = scm
 auth.ldap.password.algorithm = 6
 auth.ldap.password.rounds = 6000
 auth.ldap.password.salt_len = 16
+# "autoregister" allows users to log in to Allura with an existing LDAP account
+# If using ldap, with autoregister, you should also set "allow_user_registration"
+# to false below.
+# Set "autoregister" to false to require user to register in Allura to create
+# the LDAP record and Allura record for the user.
+auth.ldap.autoregister = true
 
 auth.allow_user_registration = true
 auth.allow_user_to_disable_account = true


[8/9] git commit: [#7406] add caching to FieldPropertyDisplayName to help non-local pref cases

Posted by br...@apache.org.
[#7406] add caching to FieldPropertyDisplayName to help non-local pref cases


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/21b5001c
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/21b5001c
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/21b5001c

Branch: refs/heads/master
Commit: 21b5001c5122c38f29b8e6937237fbf50cc1792f
Parents: 10da9e6
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Jun 12 21:55:10 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:51 2014 +0000

----------------------------------------------------------------------
 Allura/allura/model/auth.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/21b5001c/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 028e9dd..17f1175 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -199,11 +199,17 @@ class AuthGlobals(MappedClass):
 class FieldPropertyDisplayName(FieldProperty):
     # display_name is mongo field but only for preference storage
     # force all requests for this field to use the get_pref mechanism
+    # Cache it per user, since it may be re-used several times in a request
+    # and non-local preferences (ldap, database, etc) can be relatively expensive
 
     def __get__(self, instance, cls=None):
         if instance is None:
             return self
-        return instance.get_pref('display_name')
+        try:
+            display_name = instance._cache_display_name
+        except AttributeError:
+            display_name = instance._cache_display_name = instance.get_pref('display_name')
+        return display_name
 
 
 class User(MappedClass, ActivityNode, ActivityObject):


[7/9] git commit: [#7406] add timing for ldap methods

Posted by br...@apache.org.
[#7406] add timing for ldap methods


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/10da9e68
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/10da9e68
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/10da9e68

Branch: refs/heads/master
Commit: 10da9e680f476fa4552e5c5605366273e18587cc
Parents: 41c6741
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Jun 12 15:48:28 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:50 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/custom_middleware.py | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/10da9e68/Allura/allura/lib/custom_middleware.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/custom_middleware.py b/Allura/allura/lib/custom_middleware.py
index c5737f0..511c5c3 100644
--- a/Allura/allura/lib/custom_middleware.py
+++ b/Allura/allura/lib/custom_middleware.py
@@ -203,7 +203,7 @@ class AlluraTimerMiddleware(TimerMiddleware):
         import urllib2
         import activitystream
 
-        return self.entry_point_timers() + [
+        timers = self.entry_point_timers() + [
             Timer(
                 'activitystream.director.{method_name}', allura.model.timeline.Director,
                 'create_activity', 'create_timeline', 'get_timeline'),
@@ -257,6 +257,19 @@ class AlluraTimerMiddleware(TimerMiddleware):
             Timer('unified_diff', allura.model.repository, 'unified_diff'),
         ] + [Timer('sidebar', ep.load(), 'sidebar_menu') for ep in tool_entry_points]
 
+        try:
+            import ldap
+        except ImportError:
+            pass
+        else:
+            timers += [
+                Timer('ldap', ldap, 'initialize'),
+                Timer('ldap', ldap.ldapobject.LDAPObject,
+                      'bind_s', 'unbind_s', 'add_s', 'modify_s', 'search_s'),
+            ]
+
+        return timers
+
     def before_logging(self, stat_record):
         if hasattr(c, "app") and hasattr(c.app, "config"):
             stat_record.add('request_category', c.app.config.tool_name.lower())


[5/9] git commit: [#7406] factor out some ldap helper functions

Posted by br...@apache.org.
[#7406] factor out some ldap helper functions


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/30b43bbd
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/30b43bbd
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/30b43bbd

Branch: refs/heads/master
Commit: 30b43bbd7046f35105a0c076c28fd841ed5c57c0
Parents: ae304f0
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Jun 12 14:09:55 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:50 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 43 ++++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/30b43bbd/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index a1cc7e8..396da93 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -305,6 +305,24 @@ class LocalAuthenticationProvider(AuthenticationProvider):
         return datetime.utcnow()
 
 
+def ldap_conn(who=None, cred=None):
+    '''
+    Init & bind a connection with the given creds, or the admin creds if not
+    specified. Remember to unbind the connection when done.
+    '''
+    con = ldap.initialize(config['auth.ldap.server'])
+    con.bind_s(who or config['auth.ldap.admin_dn'],
+               cred or config['auth.ldap.admin_password'])
+    return con
+
+
+def ldap_user_dn(username):
+    'return a Distinguished Name for a given username'
+    return 'uid=%s,%s' % (
+        ldap.dn.escape_dn_chars(username),
+        config['auth.ldap.suffix'])
+
+
 class LdapAuthenticationProvider(AuthenticationProvider):
 
     forgotten_password_process = True
@@ -321,14 +339,9 @@ class LdapAuthenticationProvider(AuthenticationProvider):
                 return result
 
         # full registration into LDAP
-        dn_u = 'uid=%s,%s' % (
-            ldap.dn.escape_dn_chars(user_doc['username']),
-            config['auth.ldap.suffix'])
         uid = str(M.AuthGlobals.get_next_uid())
         try:
-            con = ldap.initialize(config['auth.ldap.server'])
-            con.bind_s(config['auth.ldap.admin_dn'],
-                       config['auth.ldap.admin_password'])
+            con = ldap_conn()
             uname = user_doc['username'].encode('utf-8')
             display_name = user_doc['display_name'].encode('utf-8')
             ldif_u = modlist.addModlist(dict(
@@ -343,7 +356,7 @@ class LdapAuthenticationProvider(AuthenticationProvider):
                 gecos=uname,
                 description='SCM user account'))
             try:
-                con.add_s(dn_u, ldif_u)
+                con.add_s(ldap_user_dn(user_doc['username']), ldif_u)
             except ldap.ALREADY_EXISTS:
                 log.exception('Trying to create existing user %s', uname)
                 raise
@@ -398,18 +411,14 @@ class LdapAuthenticationProvider(AuthenticationProvider):
         return M.User.query.get(username=username, disabled=False)
 
     def set_password(self, user, old_password, new_password):
-        dn = 'uid=%s,%s' % (
-                ldap.dn.escape_dn_chars(user.username),
-                config['auth.ldap.suffix'])
+        dn = ldap_user_dn(user.username)
         if old_password:
             ldap_ident = dn
             ldap_pass = old_password.encode('utf-8')
         else:
-            ldap_ident = config['auth.ldap.admin_dn']
-            ldap_pass = config['auth.ldap.admin_password']
+            ldap_ident = ldap_pass = None
         try:
-            con = ldap.initialize(config['auth.ldap.server'])
-            con.bind_s(ldap_ident, ldap_pass)
+            con = ldap_conn(ldap_ident, ldap_pass)
             new_password = self._encode_password(new_password)
             con.modify_s(
                 dn, [(ldap.MOD_REPLACE, 'userPassword', new_password)])
@@ -444,11 +453,7 @@ class LdapAuthenticationProvider(AuthenticationProvider):
     def _validate_password(self, username, password):
         '''by username'''
         try:
-            dn = 'uid=%s,%s' % (
-                ldap.dn.escape_dn_chars(username),
-                config['auth.ldap.suffix'])
-            con = ldap.initialize(config['auth.ldap.server'])
-            con.bind_s(dn, password)
+            con = ldap_conn(ldap_user_dn(username), password)
             con.unbind_s()
             return True
         except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM, ldap.NO_SUCH_OBJECT):


[4/9] git commit: [#7406] force user.display_name usage to go through prefs manager

Posted by br...@apache.org.
[#7406] force user.display_name usage to go through prefs manager


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/ff755b02
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/ff755b02
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/ff755b02

Branch: refs/heads/master
Commit: ff755b027f097fc770317d8ac7bb05c9ad380555
Parents: d84231f
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Jun 11 21:27:01 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:50 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py |  5 +++++
 Allura/allura/model/auth.py | 18 +++++++++++++++---
 2 files changed, 20 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ff755b02/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 2e6000d..697d980 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -1104,6 +1104,11 @@ class LocalUserPreferencesProvider(UserPreferencesProvider):
     def get_pref(self, user, pref_name):
         if pref_name in user.preferences:
             return user.preferences[pref_name]
+        elif pref_name == 'display_name':
+            # get the value directly from ming's internals, bypassing
+            # FieldPropertyDisplayName which always calls back to this get_pref
+            # method (infinite recursion)
+            return user.__dict__['__ming__'].state.document.display_name
         else:
             return getattr(user, pref_name)
 

http://git-wip-us.apache.org/repos/asf/allura/blob/ff755b02/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 6a9d279..df0bc16 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -196,6 +196,16 @@ class AuthGlobals(MappedClass):
         return g.next_uid
 
 
+class FieldPropertyDisplayName(FieldProperty):
+    # display_name is mongo field but only for preference storage
+    # force all requests for this field to use the get_pref mechanism
+
+    def __get__(self, instance, cls=None):
+        if instance is None:
+            return self
+        return instance.get_pref('display_name')
+
+
 class User(MappedClass, ActivityNode, ActivityObject):
     SALT_LEN = 8
 
@@ -214,15 +224,17 @@ class User(MappedClass, ActivityNode, ActivityObject):
     # full mount point: prefs dict
     tool_preferences = FieldProperty({str: {str: None}})
     tool_data = FieldProperty({str: {str: None}})  # entry point: prefs dict
-    display_name = FieldProperty(str)
     disabled = FieldProperty(bool, if_missing=False)
-    # Don't use directly, use get/set_pref() instead
+
+    # Don't use these directly, use get/set_pref() instead
     preferences = FieldProperty(dict(
         results_per_page=int,
         email_address=str,
         email_format=str,
         disable_user_messages=bool))
-
+    # Additional top-level fields can/should be accessed with get/set_pref also
+    # Not sure why we didn't put them within the 'preferences' dictionary :(
+    display_name = FieldPropertyDisplayName(str)
     # Personal data
     sex = FieldProperty(
         S.OneOf('Male', 'Female', 'Other', 'Unknown',


[3/9] git commit: [#7406] remove unused by_display_name lookups

Posted by br...@apache.org.
[#7406] remove unused by_display_name lookups


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/ae304f05
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/ae304f05
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/ae304f05

Branch: refs/heads/master
Commit: ae304f05978d12712c1086d9411c5b569a3a1c94
Parents: ff755b0
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Jun 11 21:31:20 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:50 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/helpers.py | 11 ++---------
 Allura/allura/lib/plugin.py  | 13 -------------
 Allura/allura/model/auth.py  |  4 ----
 3 files changed, 2 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ae304f05/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index ce132ba..da731ef 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -178,16 +178,9 @@ def really_unicode(s):
     return _attempt_encodings(s, encodings())
 
 
-def find_user(email=None, username=None, display_name=None):
+def find_user(email):
     from allura import model as M
-    user = None
-    if email:
-        user = M.User.by_email_address(email)
-    if not user and username:
-        user = M.User.by_username(username)
-    if not user and display_name:
-        user = M.User.by_display_name(display_name)
-    return user
+    return M.User.by_email_address(email)
 
 
 def find_project(url_path):

http://git-wip-us.apache.org/repos/asf/allura/blob/ae304f05/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 697d980..a1cc7e8 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -1056,12 +1056,6 @@ class UserPreferencesProvider(object):
         '''
         raise NotImplementedError, 'set_pref'
 
-    def find_by_display_name(self, name):
-        '''
-        :rtype: list of :class:`Users <allura.model.auth.User>`
-        '''
-        raise NotImplementedError, 'find_by_display_name'
-
     def additional_urls(self):
         '''
         Returns a mapping of additional routes for AuthProvider.
@@ -1118,13 +1112,6 @@ class LocalUserPreferencesProvider(UserPreferencesProvider):
         else:
             setattr(user, pref_name, pref_value)
 
-    def find_by_display_name(self, name):
-        from allura import model as M
-        name_regex = re.compile('(?i)%s' % re.escape(name))
-        users = M.User.query.find(dict(
-            display_name=name_regex)).sort('username').all()
-        return users
-
 
 class AdminExtension(object):
 

http://git-wip-us.apache.org/repos/asf/allura/blob/ae304f05/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index df0bc16..028e9dd 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -528,10 +528,6 @@ class User(MappedClass, ActivityNode, ActivityObject):
             return user
         return plugin.AuthenticationProvider.get(request).by_username(name)
 
-    @classmethod
-    def by_display_name(cls, name):
-        return plugin.UserPreferencesProvider.get().find_by_display_name(name)
-
     def get_tool_data(self, tool, key, default=None):
         return self.tool_data.get(tool, {}).get(key, None)
 


[6/9] git commit: [#7406] LdapUserPreferencesProvider, for display_name

Posted by br...@apache.org.
[#7406] LdapUserPreferencesProvider, for display_name


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/41c67412
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/41c67412
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/41c67412

Branch: refs/heads/master
Commit: 41c67412521835507c02b9bc85fc571068e8ce8e
Parents: 30b43bb
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Thu Jun 12 14:33:23 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:50 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 39 +++++++++++++++++++++++++++++++++++++++
 Allura/development.ini      |  7 +++++++
 Allura/setup.py             |  1 +
 3 files changed, 47 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/41c67412/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 396da93..ffe9d29 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -1118,6 +1118,45 @@ class LocalUserPreferencesProvider(UserPreferencesProvider):
             setattr(user, pref_name, pref_value)
 
 
+class LdapUserPreferencesProvider(UserPreferencesProvider):
+    '''
+    Store preferences in LDAP, falling back to LocalUserPreferencesProvider
+    '''
+
+    @LazyProperty
+    def fields(self):
+        return h.config_with_prefix(config, 'user_prefs_storage.ldap.fields.')
+
+    def get_pref(self, user, pref_name):
+        from allura import model as M
+        if pref_name in self.fields and user != M.User.anonymous():
+            con = ldap_conn()
+            try:
+                rs = con.search_s(ldap_user_dn(user.username), ldap.SCOPE_BASE)
+            except ldap.NO_SUCH_OBJECT:
+                rs = []
+            else:
+                con.unbind_s()
+            if not rs:
+                log.warning('LdapUserPref: No user record found for: {}'.format(user.username))
+                return ''
+            user_dn, user_attrs = rs[0]
+            ldap_attr = self.fields[pref_name]
+            return user_attrs[ldap_attr][0]  # assume single-valued list
+        else:
+            return LocalUserPreferencesProvider().get_pref(user, pref_name)
+
+    def set_pref(self, user, pref_name, pref_value):
+        if pref_name in self.fields:
+            con = ldap_conn()
+            ldap_attr = self.fields[pref_name]
+            con.modify_s(ldap_user_dn(user.username),
+                         [(ldap.MOD_REPLACE, ldap_attr, pref_value.encode('utf-8'))])
+            con.unbind_s()
+        else:
+            return LocalUserPreferencesProvider().set_pref(user, pref_name, pref_value)
+
+
 class AdminExtension(object):
 
     """

http://git-wip-us.apache.org/repos/asf/allura/blob/41c67412/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index c091b32..4231737 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -102,6 +102,13 @@ auth.allow_user_messages_config = true
 # In seconds
 auth.recovery_hash_expiry_period = 600
 
+user_prefs_storage.method = local
+# user_prefs_storage.method = ldap
+# If using ldap, you can specify which fields to use for a preference.
+# Any fields not specified here will be stored locally in mongo
+user_prefs_storage.ldap.fields.display_name = cn
+
+
 # Set the locations of some static resources
 #  script_name is the path that is handled by the application
 #  url_base is the prefix that references to the static resources should have

http://git-wip-us.apache.org/repos/asf/allura/blob/41c67412/Allura/setup.py
----------------------------------------------------------------------
diff --git a/Allura/setup.py b/Allura/setup.py
index 1671283..8eabf60 100644
--- a/Allura/setup.py
+++ b/Allura/setup.py
@@ -112,6 +112,7 @@ setup(
 
     [allura.user_prefs]
     local = allura.lib.plugin:LocalUserPreferencesProvider
+    ldap = allura.lib.plugin:LdapUserPreferencesProvider
 
     [allura.project_registration]
     local = allura.lib.plugin:LocalProjectRegistrationProvider


[2/9] git commit: [#7406] add option to disable user registration

Posted by br...@apache.org.
[#7406] add option to disable user registration


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/72b8f8f8
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/72b8f8f8
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/72b8f8f8

Branch: refs/heads/master
Commit: 72b8f8f8029138e872bb0d42810f2830fa72cb19
Parents: 8f1fed0
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Tue Jun 10 22:25:41 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:49 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py               |  6 +++-
 .../templates/jinja_master/theme_macros.html    |  4 ++-
 Allura/allura/tests/functional/test_auth.py     | 36 ++++++++++++++++----
 Allura/development.ini                          |  1 +
 4 files changed, 39 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/72b8f8f8/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 92b618b..892cb3b 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -118,6 +118,8 @@ class AuthController(BaseController):
 
     @expose('jinja:allura:templates/create_account.html')
     def create_account(self, **kw):
+        if not asbool(config.get('auth.allow_user_registration', True)):
+            raise wexc.HTTPNotFound()
         c.form = F.registration_form
         return dict()
 
@@ -204,12 +206,14 @@ class AuthController(BaseController):
     @require_post()
     @validate(F.registration_form, error_handler=create_account)
     def save_new(self, display_name=None, username=None, pw=None, **kw):
+        if not asbool(config.get('auth.allow_user_registration', True)):
+            raise wexc.HTTPNotFound()
         user = M.User.register(
             dict(username=username,
                  display_name=display_name,
                  password=pw))
         plugin.AuthenticationProvider.get(request).login(user)
-        flash('User "%s" registered' % user.get_pref('display_name'))
+        flash('User "%s" registered' % username)
         redirect('/')
 
     @expose()

http://git-wip-us.apache.org/repos/asf/allura/blob/72b8f8f8/Allura/allura/templates/jinja_master/theme_macros.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/jinja_master/theme_macros.html b/Allura/allura/templates/jinja_master/theme_macros.html
index 6033fe8..b828718 100644
--- a/Allura/allura/templates/jinja_master/theme_macros.html
+++ b/Allura/allura/templates/jinja_master/theme_macros.html
@@ -25,7 +25,9 @@
             <a href="{{c.user.url()}}">{{name}}</a>
             <a href="{{logout_url}}">Log Out</a>
           {% else %}
-            <a href="/auth/create_account">Register</a>
+            {% if h.asbool(config.get('auth.allow_user_registration', True)) %}
+              <a href="/auth/create_account">Register</a>
+            {% endif %}
             <a href="{{login_url}}">Log In</a>
           {% endif %}
         </nav>

http://git-wip-us.apache.org/repos/asf/allura/blob/72b8f8f8/Allura/allura/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index 73641e4..6415f69 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -18,9 +18,13 @@
 from datetime import datetime, time, timedelta
 import re
 import json
-from bson import ObjectId
 from urlparse import urlparse, parse_qs
 
+from ming.orm.ormsession import ThreadLocalORMSession, session
+from bson import ObjectId
+from pylons import tmpl_context as c
+from tg import config, expose
+from mock import patch
 import mock
 from nose.tools import (
     assert_equal,
@@ -30,15 +34,13 @@ from nose.tools import (
     assert_in,
     assert_true
 )
-from pylons import tmpl_context as c
+
 from allura.tests import TestController
 from allura.tests import decorators as td
 from alluratest.controller import setup_trove_categories
 from allura import model as M
-from ming.orm.ormsession import ThreadLocalORMSession, session
-from tg import config, expose
-from mock import patch
 from allura.lib import plugin
+from allura.lib import helpers as h
 
 
 def unentity(s):
@@ -210,7 +212,7 @@ class TestAuth(TestController):
                 pw2='12345678',
                 display_name='Test Me'))
         r = r.follow()
-        assert 'User "Test Me" registered' in unentity(r.body)
+        assert 'User "aaa" registered' in unentity(r.body)
         r = self.app.post(
             '/auth/save_new',
             params=dict(
@@ -225,6 +227,28 @@ class TestAuth(TestController):
             params=dict(username='aaa', password='12345678'),
             status=302)
 
+    def test_create_account_disabled_header_link(self):
+        with h.push_config(config, **{'auth.allow_user_registration': 'false'}):
+            r = self.app.get('/')
+            assert not 'Register' in r
+
+    def test_create_account_disabled_form_gone(self):
+        with h.push_config(config, **{'auth.allow_user_registration': 'false'}):
+            r = self.app.get('/auth/create_account', status=404)
+            assert not 'Create an Account' in r
+
+    def test_create_account_disabled_submit_fails(self):
+        with h.push_config(config, **{'auth.allow_user_registration': 'false'}):
+            self.app.post(
+                '/auth/save_new',
+                params=dict(
+                    username='aaa',
+                    pw='12345678',
+                    pw2='12345678',
+                    display_name='Test Me'),
+                status=404,
+            )
+
     def test_one_project_role(self):
         """Make sure when a user goes to a new project only one project role is created.
            There was an issue with extra project roles getting created if a user went directly to

http://git-wip-us.apache.org/repos/asf/allura/blob/72b8f8f8/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 8cc60c1..0470f67 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -86,6 +86,7 @@ auth.ldap.password.algorithm = 6
 auth.ldap.password.rounds = 6000
 auth.ldap.password.salt_len = 16
 
+auth.allow_user_registration = true
 auth.allow_user_to_disable_account = true
 auth.allow_edit_prefs = true
 auth.allow_password_change = true


[9/9] git commit: [#7406] documentation for LDAP config

Posted by br...@apache.org.
[#7406] documentation for LDAP config


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/899d1828
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/899d1828
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/899d1828

Branch: refs/heads/master
Commit: 899d18286b0072e4c3b3a85cef9d5e0fe43b1a63
Parents: 21b5001
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Jun 13 15:40:32 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Jun 19 15:52:51 2014 +0000

----------------------------------------------------------------------
 Allura/docs/installation.rst | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/899d1828/Allura/docs/installation.rst
----------------------------------------------------------------------
diff --git a/Allura/docs/installation.rst b/Allura/docs/installation.rst
index ef41f15..558f9b8 100644
--- a/Allura/docs/installation.rst
+++ b/Allura/docs/installation.rst
@@ -49,6 +49,28 @@ By default this uses port 8825.  Depending on your mail routing, you may need to
 And if the port is in use, this command will fail.  You can check the log file for any errors.
 To change the port number, edit `development.ini` and change `forgemail.port` to the appropriate port number for your environment.
 
+Using LDAP
+^^^^^^^^^^
+
+Allura has a pluggable authentication system, and can use an existing LDAP system. In your config
+file (e.g. :file:`development.ini`), there are several "ldap" settings to set:
+
+* Change auth.method to: :samp:`auth.method = ldap`
+* Set all the :samp:`auth.ldap.{*}` settings to match your LDAP server configuration. (:samp:`auth.ldap.schroot_name` won't be
+  used, don't worry about it.)
+* Keep :samp:`auth.ldap.autoregister = true` This means Allura will use existing users from your LDAP
+  server.
+* Set :samp:`auth.allow_user_registration = false` since your users already are present in LDAP.
+* Change user_prefs_storage.method to :samp:`user_prefs_storage.method = ldap`
+* Change :samp:`user_prefs_storage.ldap.fields.display_name` if needed (e.g. if display names are stored
+  in a different LDAP attribute).
+
+Restart Allura and you should be all set.  Now users can log in with their LDAP credentials and their
+Allura records will be automatically created the first time they log in.
+
+Note: if you want users to register new accounts into your LDAP system via Allura, you should turn
+off :samp:`autoregister` and turn on :samp:`allow_user_registration`
+
 Enabling RabbitMQ
 ^^^^^^^^^^^^^^^^^^