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/05/23 19:54:54 UTC

[01/11] git commit: [#7388] ticket:591 Enable forgotten password process for LDAP provider

Repository: allura
Updated Branches:
  refs/heads/master edddaf2fd -> f9c8072f5


[#7388] ticket:591 Enable forgotten password process for LDAP provider


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

Branch: refs/heads/master
Commit: bfe0f1ccbcc25f799d99c7d3ba102eae86487d2d
Parents: 505399b
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 19 10:05:08 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:44 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/bfe0f1cc/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index aaf9c10..a188190 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -289,6 +289,8 @@ class LocalAuthenticationProvider(AuthenticationProvider):
 
 class LdapAuthenticationProvider(AuthenticationProvider):
 
+    forgotten_password_process = True
+
     def register_user(self, user_doc):
         from allura import model as M
         result = M.User(**user_doc)


[04/11] git commit: [#7388] ticket:591 Hash passwords

Posted by br...@apache.org.
[#7388] ticket:591 Hash passwords

New config options:

auth.ldap.password.algorithm = 6
auth.ldap.password.rounds = 6000
auth.ldap.password.salt_len = 16


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

Branch: refs/heads/master
Commit: 102fdb426f597034e429322561e96a42277feaf9
Parents: edddaf2
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 12 10:59:29 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:44 2014 +0000

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


http://git-wip-us.apache.org/repos/asf/allura/blob/102fdb42/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index dcc8cbf..96cc870 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -23,6 +23,8 @@ import os
 import logging
 import subprocess
 import string
+import crypt
+import random
 from urllib2 import urlopen
 from cStringIO import StringIO
 from random import randint
@@ -289,7 +291,6 @@ class LdapAuthenticationProvider(AuthenticationProvider):
 
     def register_user(self, user_doc):
         from allura import model as M
-        password = user_doc['password'].encode('utf-8')
         result = M.User(**user_doc)
         dn_u = 'uid=%s,%s' % (user_doc['username'], config['auth.ldap.suffix'])
         uid = str(M.AuthGlobals.get_next_uid())
@@ -301,7 +302,7 @@ class LdapAuthenticationProvider(AuthenticationProvider):
             display_name = user_doc['display_name'].encode('utf-8')
             ldif_u = modlist.addModlist(dict(
                 uid=uname,
-                userPassword=password,
+                userPassword=self._encode_password(user_doc['password']),
                 objectClass=['account', 'posixAccount'],
                 cn=display_name,
                 uidNumber=uid,
@@ -345,6 +346,22 @@ class LdapAuthenticationProvider(AuthenticationProvider):
                               username, errmsg)
                 assert False, errmsg
 
+    def _get_salt(self, length):
+        def random_char():
+            return random.choice(string.ascii_uppercase + string.digits)
+        return ''.join(random_char() for i in range(length))
+
+    def _encode_password(self, password, salt=None):
+        cfg_prefix = 'auth.ldap.password.'
+        salt_len = asint(config[cfg_prefix + 'salt_len'])
+        algorithm = asint(config[cfg_prefix + 'algorithm'])
+        rounds = asint(config[cfg_prefix + 'rounds'])
+        salt = self._get_salt(salt_len) if salt is None else salt
+        encrypted = crypt.crypt(
+            password.encode('utf-8'),
+            '$%s$rounds=%s$%s' % (algorithm, rounds, salt))
+        return '{CRYPT}%s' % encrypted
+
     def by_username(self, username):
         from allura import model as M
         return M.User.query.get(username=username, disabled=False)
@@ -354,8 +371,9 @@ class LdapAuthenticationProvider(AuthenticationProvider):
             dn = 'uid=%s,%s' % (user.username, config['auth.ldap.suffix'])
             con = ldap.initialize(config['auth.ldap.server'])
             con.bind_s(dn, old_password.encode('utf-8'))
+            new_password = self._encode_password(new_password)
             con.modify_s(
-                dn, [(ldap.MOD_REPLACE, 'userPassword', new_password.encode('utf-8'))])
+                dn, [(ldap.MOD_REPLACE, 'userPassword', new_password)])
             con.unbind_s()
         except ldap.INVALID_CREDENTIALS:
             raise exc.HTTPUnauthorized()
@@ -387,6 +405,9 @@ class LdapAuthenticationProvider(AuthenticationProvider):
             return user._id.generation_time
         return datetime.utcnow()
 
+    def update_notifications(self, user):
+        return ''
+
 
 class ProjectRegistrationProvider(object):
     '''


[05/11] git commit: [#7388] add logging to help debug LDAP config

Posted by br...@apache.org.
[#7388] add logging to help debug LDAP config


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

Branch: refs/heads/master
Commit: 526864d61a6e8f68da80e23ca00ba90b91f204e2
Parents: a6baa40
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri May 23 17:51:53 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/auth.py | 2 ++
 Allura/allura/lib/plugin.py       | 4 ++++
 Allura/development.ini            | 2 ++
 3 files changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/526864d6/Allura/allura/controllers/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/auth.py b/Allura/allura/controllers/auth.py
index 47857f4..a0d1848 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -120,11 +120,13 @@ class AuthController(BaseController):
         user_record = M.User.query.find(
             {'tool_data.AuthPasswordReset.hash': hash}).first()
         if not user_record:
+            log.info('Reset hash not found: {}'.format(hash))
             flash('Unable to process reset, please try again')
             redirect(login_url)
         hash_expiry = user_record.get_tool_data(
             'AuthPasswordReset', 'hash_expiry')
         if not hash_expiry or hash_expiry < datetime.datetime.utcnow():
+            log.info('Reset hash expired: {} {}'.format(hash, hash_expiry))
             flash('Unable to process reset, please try again')
             redirect(login_url)
         return user_record

http://git-wip-us.apache.org/repos/asf/allura/blob/526864d6/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 5846845..fcc3aea 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -391,10 +391,13 @@ class LdapAuthenticationProvider(AuthenticationProvider):
             raise exc.HTTPUnauthorized()
 
     def _login(self):
+        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']))
             raise exc.HTTPUnauthorized()
         try:
             dn = 'uid=%s,%s' % (
@@ -404,6 +407,7 @@ class LdapAuthenticationProvider(AuthenticationProvider):
             con.bind_s(dn, self.request.params['password'])
             con.unbind_s()
         except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM):
+            log.debug('LdapAuth: could not authenticate {}'.format(user.username), exc_info=True)
             raise exc.HTTPUnauthorized()
         return user
 

http://git-wip-us.apache.org/repos/asf/allura/blob/526864d6/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index a792d44..f3e2b0c 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -81,6 +81,8 @@ auth.method = local
 # auth.logout_url = /auth/logout
 # auth.login_fragment_url = /auth/login_fragment
 
+# if using LDAP, also run `pip install python-ldap` in your Allura environment
+
 auth.ldap.server = ldap://localhost
 auth.ldap.suffix = ou=people,dc=localdomain
 auth.ldap.admin_dn = cn=admin,dc=localdomain


[10/11] git commit: [#7388] ticket:591 Add unit tests for LDAP auth provider

Posted by br...@apache.org.
[#7388] ticket:591 Add unit tests for LDAP auth provider


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

Branch: refs/heads/master
Commit: 4b2dd8d5cee61d1183e244bd2da3e8193af1a5dd
Parents: 5e5cdea
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 19 11:48:31 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 .../tests/model/test_ldap_auth_provider.py      | 99 ++++++++++++++++++++
 Allura/test.ini                                 | 11 +++
 2 files changed, 110 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/4b2dd8d5/Allura/allura/tests/model/test_ldap_auth_provider.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_ldap_auth_provider.py b/Allura/allura/tests/model/test_ldap_auth_provider.py
new file mode 100644
index 0000000..2887133
--- /dev/null
+++ b/Allura/allura/tests/model/test_ldap_auth_provider.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+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 alluratest.controller import setup_basic_test
+from allura.lib import plugin
+from allura import model as M
+
+
+class TestLdapAuthenticationProvider(object):
+
+    def setUp(self):
+        setup_basic_test()
+        self.provider = plugin.LdapAuthenticationProvider(Request.blank('/'))
+
+    def test_password_encoder(self):
+        # Verify salt
+        ep = self.provider._encode_password
+        assert_not_equal(ep('test_pass'), ep('test_pass'))
+        assert_equal(ep('test_pass', '0000'), ep('test_pass', '0000'))
+        # Test password format
+        assert_true(ep('pwd').startswith('{CRYPT}$6$rounds=6000$'))
+
+    @patch('allura.lib.plugin.ldap')
+    def test_set_password(self, ldap):
+        user = Mock(username='test-user')
+        self.provider._encode_password = Mock(return_value='new-pass-hash')
+        ldap.dn.escape_dn_chars = lambda x: x
+
+        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user.username
+        self.provider.set_password(user, 'old-pass', 'new-pass')
+        ldap.initialize.assert_called_once_with('ldaps://localhost/')
+        connection = ldap.initialize.return_value
+        connection.bind_s.called_once_with(dn, 'old-pass')
+        connection.modify_s.assert_called_once_with(
+            dn, [(ldap.MOD_REPLACE, 'userPassword', 'new-pass-hash')])
+        connection.unbind_s.assert_called_once()
+
+    @patch('allura.lib.plugin.ldap')
+    def test_login(self, ldap):
+        params = {
+            'username': 'test-user',
+            'password': 'test-password',
+        }
+        self.provider.request.method = 'POST'
+        self.provider.request.body = '&'.join(['%s=%s' % (k,v) for k,v in params.iteritems()])
+        ldap.dn.escape_dn_chars = lambda x: x
+
+        dn = 'uid=%s,ou=users,dc=sf,dc=net' % params['username']
+        self.provider._login()
+        ldap.initialize.assert_called_once_with('ldaps://localhost/')
+        connection = ldap.initialize.return_value
+        connection.bind_s.called_once_with(dn, 'test-password')
+        connection.unbind_s.assert_called_once()
+
+    @patch('allura.lib.plugin.modlist')
+    @patch('allura.lib.plugin.ldap')
+    def test_register_user(self, ldap, modlist):
+        user_doc = {
+            'username': u'new-user',
+            'display_name': u'New User',
+            'password': u'new-password',
+        }
+        ldap.dn.escape_dn_chars = lambda x: x
+        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)
+        ThreadLocalORMSession.flush_all()
+        assert_not_equal(M.User.query.get(username=user_doc['username']), None)
+
+        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user_doc['username']
+        ldap.initialize.assert_called_once_with('ldaps://localhost/')
+        connection = ldap.initialize.return_value
+        connection.bind_s.called_once_with(
+            'cn=site,ou=admin,dc=sf,dc=net',
+            'admin-password')
+        connection.add_s.assert_called_once_with(dn, modlist.addModlist.return_value)
+        connection.unbind_s.assert_called_once()

http://git-wip-us.apache.org/repos/asf/allura/blob/4b2dd8d5/Allura/test.ini
----------------------------------------------------------------------
diff --git a/Allura/test.ini b/Allura/test.ini
index a82fbf2..b82be62 100644
--- a/Allura/test.ini
+++ b/Allura/test.ini
@@ -136,6 +136,17 @@ markdown_render_max_length = 40000
 user_message.time_interval = 3600
 user_message.max_messages = 200
 
+# LDAP auth provider
+auth.ldap.server = ldaps://localhost/
+auth.ldap.suffix = ou=users,dc=sf,dc=net
+auth.ldap.admin_dn = cn=site,ou=admin,dc=sf,dc=net
+auth.ldap.admin_password = admin-password
+auth.ldap.use_schroot = False
+auth.ldap.password.algorithm = 6
+auth.ldap.password.rounds = 6000
+auth.ldap.password.salt_len = 16
+
+
 [app:main_with_amqp]
 use = main
 # Use test RabbitMQ vhost


[09/11] git commit: [#7388] remove old config entries

Posted by br...@apache.org.
[#7388] remove old config entries


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

Branch: refs/heads/master
Commit: 0ba1ee4dfc195a5ae90d90c6d7bd867b7b12ec77
Parents: 526864d
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri May 23 17:52:06 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 Allura/development.ini | 13 -------------
 Allura/test.ini        |  2 --
 2 files changed, 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/0ba1ee4d/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index f3e2b0c..124afaa 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -58,15 +58,6 @@ beaker.session.type = cookie
 beaker.session.secret = 61ece7db-ba8d-49fe-a923-ab444741708c
 beaker.session.validate_key = 714bfe3612c42390726f
 
-# Used to retrieve project info from SFX for private projects
-sfx.secret = my-secret-key
-
-# Used for migrate urls to ForgeShortUrl
-sfx.hostedapps_db.hostname = localhost
-sfx.hostedapps_db.port = 3306
-sfx.hostedapps_db.username = root
-sfx.hostedapps_db.password = 0000
-
 # Google Analytics account for tracking
 # ga.account = UA-XXXXX-X
 
@@ -147,10 +138,6 @@ scm.clone.ro.svn = svn checkout $source_url $dest_path
 scm.clone.https_anon.svn = svn checkout $source_url $dest_path
 scm.clone.svn = svn checkout --username=$username $source_url $dest_path
 
-scm.new_refresh = true
-
-gitweb.cgi = /usr/lib/cgi-bin/gitweb.cgi
-
 scm.repos.root = /srv
 scm.repos.tarball.enable = false
 scm.repos.tarball.root = /usr/share/nginx/www/

http://git-wip-us.apache.org/repos/asf/allura/blob/0ba1ee4d/Allura/test.ini
----------------------------------------------------------------------
diff --git a/Allura/test.ini b/Allura/test.ini
index b82be62..f6c9ae0 100644
--- a/Allura/test.ini
+++ b/Allura/test.ini
@@ -93,8 +93,6 @@ ew.url_base = /nf/_ew_/
 static.script_name = /nf/_static_/
 static.url_base = /nf/_static_/
 
-scm.new_refresh = true
-
 scm.host.ro.git = git://git.localhost$path
 scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
 scm.host.https.git = https://$username@localhost:8022/scm-repo$path


[03/11] git commit: [#7388] ticket:591 Fix indentation

Posted by br...@apache.org.
[#7388] ticket:591 Fix indentation


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

Branch: refs/heads/master
Commit: e59920942cc283e8319aea3f4623ae6f97f047b6
Parents: 102fdb4
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri May 16 11:13:40 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:44 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/e5992094/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 96cc870..4575ab7 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -332,19 +332,19 @@ class LdapAuthenticationProvider(AuthenticationProvider):
         return result
 
     def upload_sshkey(self, username, pubkey):
-            if not asbool(config.get('auth.ldap.use_schroot', True)):
-                raise NotImplemented, 'SSH keys are not supported'
-
-            argv = ('schroot -d / -c %s -u root /ldap-userconfig.py upload %s' % (
-                config['auth.ldap.schroot_name'], username)).split() + [pubkey]
-            p = subprocess.Popen(
-                argv, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-            rc = p.wait()
-            if rc != 0:
-                errmsg = p.stdout.read()
-                log.exception('Error uploading public SSH key for %s: %s',
-                              username, errmsg)
-                assert False, errmsg
+        if not asbool(config.get('auth.ldap.use_schroot', True)):
+            raise NotImplemented, 'SSH keys are not supported'
+
+        argv = ('schroot -d / -c %s -u root /ldap-userconfig.py upload %s' % (
+            config['auth.ldap.schroot_name'], username)).split() + [pubkey]
+        p = subprocess.Popen(
+            argv, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        rc = p.wait()
+        if rc != 0:
+            errmsg = p.stdout.read()
+            log.exception('Error uploading public SSH key for %s: %s',
+                          username, errmsg)
+            assert False, errmsg
 
     def _get_salt(self, length):
         def random_char():


[11/11] git commit: [#7388] move new test file to slightly better directory

Posted by br...@apache.org.
[#7388] move new test file to slightly better directory


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

Branch: refs/heads/master
Commit: f9c8072f56b90106910b7460b7acffd634122fd1
Parents: 0ba1ee4
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri May 23 17:52:47 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 .../tests/model/test_ldap_auth_provider.py      | 99 --------------------
 .../tests/unit/test_ldap_auth_provider.py       | 99 ++++++++++++++++++++
 2 files changed, 99 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/f9c8072f/Allura/allura/tests/model/test_ldap_auth_provider.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_ldap_auth_provider.py b/Allura/allura/tests/model/test_ldap_auth_provider.py
deleted file mode 100644
index 2887133..0000000
--- a/Allura/allura/tests/model/test_ldap_auth_provider.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# -*- coding: utf-8 -*-
-
-#       Licensed to the Apache Software Foundation (ASF) under one
-#       or more contributor license agreements.  See the NOTICE file
-#       distributed with this work for additional information
-#       regarding copyright ownership.  The ASF licenses this file
-#       to you under the Apache License, Version 2.0 (the
-#       "License"); you may not use this file except in compliance
-#       with the License.  You may obtain a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#       Unless required by applicable law or agreed to in writing,
-#       software distributed under the License is distributed on an
-#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#       KIND, either express or implied.  See the License for the
-#       specific language governing permissions and limitations
-#       under the License.
-
-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 alluratest.controller import setup_basic_test
-from allura.lib import plugin
-from allura import model as M
-
-
-class TestLdapAuthenticationProvider(object):
-
-    def setUp(self):
-        setup_basic_test()
-        self.provider = plugin.LdapAuthenticationProvider(Request.blank('/'))
-
-    def test_password_encoder(self):
-        # Verify salt
-        ep = self.provider._encode_password
-        assert_not_equal(ep('test_pass'), ep('test_pass'))
-        assert_equal(ep('test_pass', '0000'), ep('test_pass', '0000'))
-        # Test password format
-        assert_true(ep('pwd').startswith('{CRYPT}$6$rounds=6000$'))
-
-    @patch('allura.lib.plugin.ldap')
-    def test_set_password(self, ldap):
-        user = Mock(username='test-user')
-        self.provider._encode_password = Mock(return_value='new-pass-hash')
-        ldap.dn.escape_dn_chars = lambda x: x
-
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user.username
-        self.provider.set_password(user, 'old-pass', 'new-pass')
-        ldap.initialize.assert_called_once_with('ldaps://localhost/')
-        connection = ldap.initialize.return_value
-        connection.bind_s.called_once_with(dn, 'old-pass')
-        connection.modify_s.assert_called_once_with(
-            dn, [(ldap.MOD_REPLACE, 'userPassword', 'new-pass-hash')])
-        connection.unbind_s.assert_called_once()
-
-    @patch('allura.lib.plugin.ldap')
-    def test_login(self, ldap):
-        params = {
-            'username': 'test-user',
-            'password': 'test-password',
-        }
-        self.provider.request.method = 'POST'
-        self.provider.request.body = '&'.join(['%s=%s' % (k,v) for k,v in params.iteritems()])
-        ldap.dn.escape_dn_chars = lambda x: x
-
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % params['username']
-        self.provider._login()
-        ldap.initialize.assert_called_once_with('ldaps://localhost/')
-        connection = ldap.initialize.return_value
-        connection.bind_s.called_once_with(dn, 'test-password')
-        connection.unbind_s.assert_called_once()
-
-    @patch('allura.lib.plugin.modlist')
-    @patch('allura.lib.plugin.ldap')
-    def test_register_user(self, ldap, modlist):
-        user_doc = {
-            'username': u'new-user',
-            'display_name': u'New User',
-            'password': u'new-password',
-        }
-        ldap.dn.escape_dn_chars = lambda x: x
-        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)
-        ThreadLocalORMSession.flush_all()
-        assert_not_equal(M.User.query.get(username=user_doc['username']), None)
-
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user_doc['username']
-        ldap.initialize.assert_called_once_with('ldaps://localhost/')
-        connection = ldap.initialize.return_value
-        connection.bind_s.called_once_with(
-            'cn=site,ou=admin,dc=sf,dc=net',
-            'admin-password')
-        connection.add_s.assert_called_once_with(dn, modlist.addModlist.return_value)
-        connection.unbind_s.assert_called_once()

http://git-wip-us.apache.org/repos/asf/allura/blob/f9c8072f/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
new file mode 100644
index 0000000..2887133
--- /dev/null
+++ b/Allura/allura/tests/unit/test_ldap_auth_provider.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+
+#       Licensed to the Apache Software Foundation (ASF) under one
+#       or more contributor license agreements.  See the NOTICE file
+#       distributed with this work for additional information
+#       regarding copyright ownership.  The ASF licenses this file
+#       to you under the Apache License, Version 2.0 (the
+#       "License"); you may not use this file except in compliance
+#       with the License.  You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#       Unless required by applicable law or agreed to in writing,
+#       software distributed under the License is distributed on an
+#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#       KIND, either express or implied.  See the License for the
+#       specific language governing permissions and limitations
+#       under the License.
+
+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 alluratest.controller import setup_basic_test
+from allura.lib import plugin
+from allura import model as M
+
+
+class TestLdapAuthenticationProvider(object):
+
+    def setUp(self):
+        setup_basic_test()
+        self.provider = plugin.LdapAuthenticationProvider(Request.blank('/'))
+
+    def test_password_encoder(self):
+        # Verify salt
+        ep = self.provider._encode_password
+        assert_not_equal(ep('test_pass'), ep('test_pass'))
+        assert_equal(ep('test_pass', '0000'), ep('test_pass', '0000'))
+        # Test password format
+        assert_true(ep('pwd').startswith('{CRYPT}$6$rounds=6000$'))
+
+    @patch('allura.lib.plugin.ldap')
+    def test_set_password(self, ldap):
+        user = Mock(username='test-user')
+        self.provider._encode_password = Mock(return_value='new-pass-hash')
+        ldap.dn.escape_dn_chars = lambda x: x
+
+        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user.username
+        self.provider.set_password(user, 'old-pass', 'new-pass')
+        ldap.initialize.assert_called_once_with('ldaps://localhost/')
+        connection = ldap.initialize.return_value
+        connection.bind_s.called_once_with(dn, 'old-pass')
+        connection.modify_s.assert_called_once_with(
+            dn, [(ldap.MOD_REPLACE, 'userPassword', 'new-pass-hash')])
+        connection.unbind_s.assert_called_once()
+
+    @patch('allura.lib.plugin.ldap')
+    def test_login(self, ldap):
+        params = {
+            'username': 'test-user',
+            'password': 'test-password',
+        }
+        self.provider.request.method = 'POST'
+        self.provider.request.body = '&'.join(['%s=%s' % (k,v) for k,v in params.iteritems()])
+        ldap.dn.escape_dn_chars = lambda x: x
+
+        dn = 'uid=%s,ou=users,dc=sf,dc=net' % params['username']
+        self.provider._login()
+        ldap.initialize.assert_called_once_with('ldaps://localhost/')
+        connection = ldap.initialize.return_value
+        connection.bind_s.called_once_with(dn, 'test-password')
+        connection.unbind_s.assert_called_once()
+
+    @patch('allura.lib.plugin.modlist')
+    @patch('allura.lib.plugin.ldap')
+    def test_register_user(self, ldap, modlist):
+        user_doc = {
+            'username': u'new-user',
+            'display_name': u'New User',
+            'password': u'new-password',
+        }
+        ldap.dn.escape_dn_chars = lambda x: x
+        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)
+        ThreadLocalORMSession.flush_all()
+        assert_not_equal(M.User.query.get(username=user_doc['username']), None)
+
+        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user_doc['username']
+        ldap.initialize.assert_called_once_with('ldaps://localhost/')
+        connection = ldap.initialize.return_value
+        connection.bind_s.called_once_with(
+            'cn=site,ou=admin,dc=sf,dc=net',
+            'admin-password')
+        connection.add_s.assert_called_once_with(dn, modlist.addModlist.return_value)
+        connection.unbind_s.assert_called_once()


[07/11] git commit: [#7388] ticket:591 Catch exception raised when trying to login with empty password and valid username

Posted by br...@apache.org.
[#7388] ticket:591 Catch exception raised when trying to login with empty password and valid username


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

Branch: refs/heads/master
Commit: 5e5cdea570e993a71cd377b30322e2c6c92313b6
Parents: 78d63bf
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 19 10:25:11 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/5e5cdea5/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 40683b9..2de236f 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -403,7 +403,7 @@ class LdapAuthenticationProvider(AuthenticationProvider):
             con = ldap.initialize(config['auth.ldap.server'])
             con.bind_s(dn, self.request.params['password'])
             con.unbind_s()
-        except ldap.INVALID_CREDENTIALS:
+        except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM):
             raise exc.HTTPUnauthorized()
         return user
 


[08/11] git commit: [#7388] provide default new config values

Posted by br...@apache.org.
[#7388] provide default new config values


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

Branch: refs/heads/master
Commit: a6baa40dc9025f2023fa7234de0a2da0813e3641
Parents: 4b2dd8d
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri May 23 17:51:11 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 6 +++---
 Allura/development.ini      | 3 +++
 2 files changed, 6 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a6baa40d/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 2de236f..5846845 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -357,9 +357,9 @@ class LdapAuthenticationProvider(AuthenticationProvider):
 
     def _encode_password(self, password, salt=None):
         cfg_prefix = 'auth.ldap.password.'
-        salt_len = asint(config[cfg_prefix + 'salt_len'])
-        algorithm = asint(config[cfg_prefix + 'algorithm'])
-        rounds = asint(config[cfg_prefix + 'rounds'])
+        salt_len = asint(config.get(cfg_prefix + 'salt_len', 16))
+        algorithm = config.get(cfg_prefix + 'algorithm', 6)
+        rounds = asint(config.get(cfg_prefix + 'rounds', 6000))
         salt = self._get_salt(salt_len) if salt is None else salt
         encrypted = crypt.crypt(
             password.encode('utf-8'),

http://git-wip-us.apache.org/repos/asf/allura/blob/a6baa40d/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 172cafb..a792d44 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -86,6 +86,9 @@ auth.ldap.suffix = ou=people,dc=localdomain
 auth.ldap.admin_dn = cn=admin,dc=localdomain
 auth.ldap.admin_password = secret
 auth.ldap.schroot_name = scm
+auth.ldap.password.algorithm = 6
+auth.ldap.password.rounds = 6000
+auth.ldap.password.salt_len = 16
 
 # In seconds
 auth.recovery_hash_expiry_period = 600


[02/11] git commit: [#7388] ticket:591 Handle case when no old password is provided

Posted by br...@apache.org.
[#7388] ticket:591 Handle case when no old password is provided


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

Branch: refs/heads/master
Commit: 505399b5a5b16da6e7d00d16c5dbc79d94c9444f
Parents: e599209
Author: Igor Bondarenko <je...@gmail.com>
Authored: Fri May 16 11:22:39 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:44 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/505399b5/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 4575ab7..aaf9c10 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -367,10 +367,16 @@ 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' % (user.username, config['auth.ldap.suffix'])
+        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']
         try:
-            dn = 'uid=%s,%s' % (user.username, config['auth.ldap.suffix'])
             con = ldap.initialize(config['auth.ldap.server'])
-            con.bind_s(dn, old_password.encode('utf-8'))
+            con.bind_s(ldap_ident, ldap_pass)
             new_password = self._encode_password(new_password)
             con.modify_s(
                 dn, [(ldap.MOD_REPLACE, 'userPassword', new_password)])


[06/11] git commit: [#7388] ticket:591 Escape DN's when constructing from username

Posted by br...@apache.org.
[#7388] ticket:591 Escape DN's when constructing from username


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

Branch: refs/heads/master
Commit: 78d63bfb922203d09b6269e7ea74218723eaa6ec
Parents: bfe0f1c
Author: Igor Bondarenko <je...@gmail.com>
Authored: Mon May 19 10:11:07 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri May 23 17:53:45 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/78d63bfb/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index a188190..40683b9 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -294,7 +294,9 @@ class LdapAuthenticationProvider(AuthenticationProvider):
     def register_user(self, user_doc):
         from allura import model as M
         result = M.User(**user_doc)
-        dn_u = 'uid=%s,%s' % (user_doc['username'], config['auth.ldap.suffix'])
+        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'])
@@ -369,7 +371,9 @@ 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' % (user.username, config['auth.ldap.suffix'])
+        dn = 'uid=%s,%s' % (
+                ldap.dn.escape_dn_chars(user.username),
+                config['auth.ldap.suffix'])
         if old_password:
             ldap_ident = dn
             ldap_pass = old_password.encode('utf-8')
@@ -393,7 +397,9 @@ class LdapAuthenticationProvider(AuthenticationProvider):
         if user is None:
             raise exc.HTTPUnauthorized()
         try:
-            dn = 'uid=%s,%s' % (user.username, config['auth.ldap.suffix'])
+            dn = 'uid=%s,%s' % (
+                    ldap.dn.escape_dn_chars(user.username),
+                    config['auth.ldap.suffix'])
             con = ldap.initialize(config['auth.ldap.server'])
             con.bind_s(dn, self.request.params['password'])
             con.unbind_s()