allura git commit: [#8128] show 2FA+HTTP checkout message when needed

2016-09-22 Thread brondsem
Repository: allura
Updated Branches:
  refs/heads/db/8128 6ac5a2c26 -> 9e0469d50


[#8128] show 2FA+HTTP checkout message when needed


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

Branch: refs/heads/db/8128
Commit: 9e0469d50370c32bc641075c224be355a83de1c0
Parents: 6ac5a2c
Author: Dave Brondsema 
Authored: Thu Sep 22 16:43:43 2016 -0400
Committer: Dave Brondsema 
Committed: Thu Sep 22 16:43:43 2016 -0400

--
 Allura/allura/templates/repo/repo_master.html | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)
--


http://git-wip-us.apache.org/repos/asf/allura/blob/9e0469d5/Allura/allura/templates/repo/repo_master.html
--
diff --git a/Allura/allura/templates/repo/repo_master.html 
b/Allura/allura/templates/repo/repo_master.html
index 1d94285..eb51f79 100644
--- a/Allura/allura/templates/repo/repo_master.html
+++ b/Allura/allura/templates/repo/repo_master.html
@@ -38,10 +38,16 @@
   $('#access_urls .btn').click(function(evt){
 evt.preventDefault();
 var parent = $(this).parents('.btn-bar');
-$(parent).find('input').val($(this).attr('data-url'));
+var checkout_cmd = $(this).attr('data-url');
+$(parent).find('input').val(checkout_cmd);
 $(parent).find('span').text($(this).attr('title')+' access');
 $(this).parent().children('.btn').removeClass('active');
 $(this).addClass('active');
+if (checkout_cmd.indexOf(' http://') !== -1 || checkout_cmd.indexOf(' 
https://') !== -1 ) {
+  $('#http-2fa-msg').show();
+} else {
+  $('#http-2fa-msg').hide();
+}
   });
   $('#access_urls .btn').first().click();
 
@@ -110,6 +116,12 @@
  class="selectText"
  value=""/>
 
+{% if not c.user.is_anonymous() and c.user.get_pref('multifactor') and 
h.has_access(c.app, 'write') %}
+
+When using HTTP access with two-factor auth, you will need to enter 
your password and current token together as
+the password (e.g. "p4ssw0Rd123456")
+
+{% endif %}
 
   {% endif %}
 {% endmacro %}



allura git commit: [#8131] use correct field name in LastCommitDoc queries

2016-09-22 Thread brondsem
Repository: allura
Updated Branches:
  refs/heads/db/8131 [created] d9c9df551


[#8131] use correct field name in LastCommitDoc queries


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

Branch: refs/heads/db/8131
Commit: d9c9df551fb951ee0658bb360e8930251e997563
Parents: 7fb4022
Author: Dave Brondsema 
Authored: Thu Sep 22 15:29:15 2016 -0400
Committer: Dave Brondsema 
Committed: Thu Sep 22 15:29:15 2016 -0400

--
 Allura/allura/scripts/refreshrepo.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/allura/blob/d9c9df55/Allura/allura/scripts/refreshrepo.py
--
diff --git a/Allura/allura/scripts/refreshrepo.py 
b/Allura/allura/scripts/refreshrepo.py
index fbec016..115e5a4 100644
--- a/Allura/allura/scripts/refreshrepo.py
+++ b/Allura/allura/scripts/refreshrepo.py
@@ -111,12 +111,12 @@ class RefreshRepo(ScriptTask):
 
 # delete LastCommitDocs
 i = M.repository.LastCommitDoc.m.find(
-dict(commit_ids={'$in': ci_ids_chunk})).count()
+dict(commit_id={'$in': ci_ids_chunk})).count()
 if i:
 log.info(
 "Deleting %i remaining LastCommitDoc docs, 
by repo id...", i)
 M.repository.LastCommitDoc.m.remove(
-dict(commit_ids={'$in': ci_ids_chunk}))
+dict(commit_id={'$in': ci_ids_chunk}))
 
 i = M.repository.CommitRunDoc.m.find(
 {"commit_ids": {"$in": ci_ids_chunk}}).count()



allura git commit: [#8130] invalidate other login sessions after setting up two-factor auth

2016-09-22 Thread brondsem
Repository: allura
Updated Branches:
  refs/heads/master e30522555 -> 7fb402233


[#8130] invalidate other login sessions after setting up two-factor auth


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

Branch: refs/heads/master
Commit: 7fb4022335055d605b571f538cff5661df509fff
Parents: e305225
Author: Dave Brondsema 
Authored: Tue Sep 20 16:44:01 2016 -0400
Committer: Dave Brondsema 
Committed: Tue Sep 20 16:44:01 2016 -0400

--
 Allura/allura/controllers/auth.py   |  3 +++
 Allura/allura/lib/plugin.py | 16 +++-
 Allura/allura/tests/functional/test_auth.py | 10 ++
 3 files changed, 24 insertions(+), 5 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/allura/blob/7fb40223/Allura/allura/controllers/auth.py
--
diff --git a/Allura/allura/controllers/auth.py 
b/Allura/allura/controllers/auth.py
index a5031d1..932f106 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -731,6 +731,8 @@ class PreferencesController(BaseController):
 h.auditlog_user('Set up multifactor TOTP')
 totp_service.set_secret_key(c.user, key)
 c.user.set_pref('multifactor', True)
+c.user.set_tool_data('allura', multifactor_date=datetime.utcnow())
+c.user.set_tool_data('allura', 
pwd_reset_preserve_session=session.id)  # other sessions will have to re-auth; 
preserve this one
 del session['totp_new_key']
 session.save()
 tg.flash('Two factor authentication has now been set up.')
@@ -754,6 +756,7 @@ class PreferencesController(BaseController):
 recovery = RecoveryCodeService.get()
 recovery.delete_all(c.user)
 c.user.set_pref('multifactor', False)
+c.user.set_tool_data('allura', multifactor_date=None)
 tg.flash('Multifactor authentication has now been disabled.')
 email_body = 
g.jinja2_env.get_template('allura:templates/mail/twofactor_disabled.md').render(dict(
 user=c.user,

http://git-wip-us.apache.org/repos/asf/allura/blob/7fb40223/Allura/allura/lib/plugin.py
--
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index 7127120..4b2bf0a 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -118,11 +118,17 @@ class AuthenticationProvider(object):
 if user.disabled or user.pending:
 self.logout()
 return M.User.anonymous()
-if not user.is_anonymous() and \
-self.get_last_password_updated(user) > 
datetime.utcfromtimestamp(self.session.created) and \
-user.get_tool_data('allura', 'pwd_reset_preserve_session') != 
self.session.id:
-log.debug('Session logged out: due to user %s pwd change %s > %s', 
user.username,
-  self.get_last_password_updated(user), 
datetime.utcfromtimestamp(self.session.created))
+session_create_date = datetime.utcfromtimestamp(self.session.created)
+if user.is_anonymous():
+sessions_need_reauth = False
+elif self.get_last_password_updated(user) > session_create_date:
+sessions_need_reauth = True
+elif (user.get_tool_data('allura', 'multifactor_date') or 
datetime.min) > session_create_date:
+sessions_need_reauth = True
+else:
+sessions_need_reauth = False
+if sessions_need_reauth and user.get_tool_data('allura', 
'pwd_reset_preserve_session') != self.session.id:
+log.debug('Session logged out: due to user %s pwd change or 
multifactor enabled', user.username)
 self.logout()
 return M.User.anonymous()
 

http://git-wip-us.apache.org/repos/asf/allura/blob/7fb40223/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 4ba27e3..b7b28be 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -2093,6 +2093,11 @@ class TestTwoFactor(TestController):
 assert_in('Password Confirmation', r)
 
 def test_enable_totp(self):
+# create a separate session, for later use in the test
+other_session = TestController()
+other_session.setUp()
+other_session.app.get('/auth/preferences/')
+
 with out_audits(user=True):
 r 

[3/3] allura git commit: Make this test run successfully on its own

2016-09-22 Thread brondsem
Make this test run successfully on its own


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

Branch: refs/heads/db/parallel_test_improvements
Commit: 8a70d6e45b33d35a95a01fe3c623a2d94557
Parents: 46dc9f9
Author: Dave Brondsema 
Authored: Thu Sep 22 10:16:04 2016 -0400
Committer: Dave Brondsema 
Committed: Thu Sep 22 10:16:04 2016 -0400

--
 ForgeImporters/forgeimporters/tests/github/test_tasks.py | 1 +
 1 file changed, 1 insertion(+)
--


http://git-wip-us.apache.org/repos/asf/allura/blob/8a70d6e4/ForgeImporters/forgeimporters/tests/github/test_tasks.py
--
diff --git a/ForgeImporters/forgeimporters/tests/github/test_tasks.py 
b/ForgeImporters/forgeimporters/tests/github/test_tasks.py
index cf58644..b048407 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_tasks.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_tasks.py
@@ -23,6 +23,7 @@ from ...github import tasks
 @mock.patch.object(tasks, 'GitHubProjectExtractor')
 @mock.patch.object(tasks, 'ThreadLocalORMSession')
 @mock.patch.object(tasks, 'c')
+@mock.patch.object(tasks, 'g', mock.MagicMock())
 def test_import_project_info(c, session, ghpe):
 c.project = mock.Mock(name='project')
 c.user = mock.Mock(name='user')



[2/3] allura git commit: Split up pylint test into chunks that can be run with nose multiprocess; move pyflakes chunks into parallelized pattern

2016-09-22 Thread brondsem
Split up pylint test into chunks that can be run with nose multiprocess; move 
pyflakes chunks into parallelized pattern


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

Branch: refs/heads/db/parallel_test_improvements
Commit: 46dc9f9bc0a026e0b555add0dbd5e90cea4a7462
Parents: 1969390
Author: Dave Brondsema 
Authored: Wed Sep 21 14:32:35 2016 -0400
Committer: Dave Brondsema 
Committed: Wed Sep 21 14:32:35 2016 -0400

--
 AlluraTest/alluratest/test_syntax.py | 89 +--
 1 file changed, 50 insertions(+), 39 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/allura/blob/46dc9f9b/AlluraTest/alluratest/test_syntax.py
--
diff --git a/AlluraTest/alluratest/test_syntax.py 
b/AlluraTest/alluratest/test_syntax.py
index d29b00b..1db63c9 100644
--- a/AlluraTest/alluratest/test_syntax.py
+++ b/AlluraTest/alluratest/test_syntax.py
@@ -18,6 +18,7 @@
 import os.path
 from subprocess import Popen, PIPE
 import sys
+from itertools import izip_longest
 
 toplevel_dir = os.path.abspath(os.path.dirname(__file__) + "/../..")
 
@@ -30,52 +31,17 @@ def run(cmd):
 sys.stderr.write(stderr)
 return proc.returncode
 
-find_py = "find Allura Forge* -name '*.py'"
 
-# a recepe from itertools doc
-from itertools import izip_longest
+find_py = "find Allura Forge* -name '*.py'"
 
 
+# a recipe from itertools doc
 def grouper(n, iterable, fillvalue=None):
 "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
 args = [iter(iterable)] * n
 return izip_longest(fillvalue=fillvalue, *args)
 
 
-def test_pyflakes():
-# skip some that aren't critical errors
-skips = [
-'imported but unused',
-'redefinition of unused',
-'assigned to but never used',
-'__version__',
-]
-proc = Popen(find_py, shell=True, cwd=toplevel_dir,
- stdout=PIPE, stderr=PIPE)
-(find_stdout, stderr) = proc.communicate()
-sys.stderr.write(stderr)
-assert proc.returncode == 0, proc.returncode
-
-# run pyflakes in batches, so it doesn't take tons of memory
-error = False
-all_files = [f for f in find_stdout.split('\n')
- if '/migrations/' not in f and f.strip()]
-for files in grouper(20, all_files, fillvalue=''):
-cmd = "pyflakes " + \
-' '.join(files) + " | grep -v '" + \
-"' | grep -v '".join(skips) + "'"
-# print 'Command was: %s' % cmd
-retval = run(cmd)
-if retval != 1:
-print
-# print 'Command was: %s' % cmd
-print 'Returned %s' % retval
-error = True
-
-if error:
-raise Exception('pyflakes failure, see stdout')
-
-
 def test_no_local_tz_functions():
 if run(find_py + " | xargs grep '\.now(' ") not in [1, 123]:
 raise Exception("These should use .utcnow()")
@@ -104,6 +70,51 @@ def test_no_tabs():
 if run(find_py + " | xargs grep '  ' ") not in [1, 123]:
 raise Exception('These should not use tab chars')
 
-def test_linters():
-if run(find_py + ' | xargs pylint -E --disable=all 
--enable=exposed-api-needs-kwargs --load-plugins alluratest.pylint_checkers') 
!= 0:
+
+def run_linter(files):
+if run('pylint -E --disable=all --enable=exposed-api-needs-kwargs 
--load-plugins alluratest.pylint_checkers {}'.format(' '.join(files))) != 0:
 raise Exception('Custom Allura pylint errors found.')
+
+
+def run_pyflakes(files):
+# skip some that aren't critical errors
+skips = [
+'imported but unused',
+'redefinition of unused',
+'assigned to but never used',
+'__version__',
+]
+files = [f for f in files if '/migrations/' not in f]
+cmd = "pyflakes " + ' '.join(files) + " | grep -v '" + "' | grep -v 
'".join(skips) + "'"
+if run(cmd) != 1:
+# print 'Command was: %s' % cmd
+raise Exception('pyflakes failure, see stdout')
+
+
+class TestLinters(object):
+# this will get populated dynamically with test methods, see below
+pass
+
+
+# Dynamically generate many test methods, to run pylint & pyflakes commands in 
separate batches
+# Can't use 
http://nose.readthedocs.io/en/latest/writing_tests.html#test-generators because 
nose doesn't run
+# those in parallel
+def create_many_lint_methods():
+proc = Popen(find_py, shell=True, cwd=toplevel_dir, stdout=PIPE, 
stderr=PIPE)
+(find_stdout, stderr) = proc.communicate()
+sys.stderr.write(stderr)
+assert proc.returncode == 0, proc.returncode
+py_files = find_stdout.split('\n')
+
+for i, files in 

[1/3] allura git commit: Make these test classes runnable on their own (they happen to pass if other stuff runs first)

2016-09-22 Thread brondsem
Repository: allura
Updated Branches:
  refs/heads/db/parallel_test_improvements [created] 8a70d6e45


Make these test classes runnable on their own (they happen to pass if other 
stuff runs first)


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

Branch: refs/heads/db/parallel_test_improvements
Commit: 1969390a5a4d2d2428b6e50244d3409bf6d1278c
Parents: e305225
Author: Dave Brondsema 
Authored: Wed Sep 21 14:28:36 2016 -0400
Committer: Dave Brondsema 
Committed: Wed Sep 21 14:28:36 2016 -0400

--
 .../forgeimporters/tests/forge/test_tracker.py | 13 ++---
 .../forgeimporters/tests/github/test_tracker.py| 10 ++
 2 files changed, 20 insertions(+), 3 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/allura/blob/1969390a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
--
diff --git a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py 
b/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
index e985763..9be7743 100644
--- a/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/forge/test_tracker.py
@@ -17,8 +17,6 @@
 
 from datetime import datetime
 from unittest import TestCase
-from cgi import FieldStorage
-from cStringIO import StringIO
 
 import mock
 from ming.odm import ThreadLocalORMSession
@@ -29,11 +27,20 @@ from allura.tests.decorators import with_tracker
 
 from allura import model as M
 from forgeimporters.forge import tracker
-from forgetracker import model as TM
 
 
 class TestTrackerImporter(TestCase):
 
+def setUp(self):
+super(TestTrackerImporter, self).setUp()
+# every single test method here creates an importer and 
ToolImporterMeta uses 'g'
+self.patcher_g = mock.patch('forgeimporters.base.g', mock.MagicMock())
+self.patcher_g.start()
+
+def tearDown(self):
+super(TestTrackerImporter, self).tearDown()
+self.patcher_g.stop()
+
 @mock.patch.object(tracker, 'File')
 @mock.patch.object(tracker.h, 'make_app_admin_only')
 @mock.patch.object(tracker, 'g')

http://git-wip-us.apache.org/repos/asf/allura/blob/1969390a/ForgeImporters/forgeimporters/tests/github/test_tracker.py
--
diff --git a/ForgeImporters/forgeimporters/tests/github/test_tracker.py 
b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
index e02ac5a..fd7df5c 100644
--- a/ForgeImporters/forgeimporters/tests/github/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/github/test_tracker.py
@@ -26,6 +26,16 @@ from forgeimporters.github.utils import 
GitHubMarkdownConverter
 
 class TestTrackerImporter(TestCase):
 
+def setUp(self):
+super(TestTrackerImporter, self).setUp()
+# every single test method here creates an importer and 
ToolImporterMeta uses 'g'
+self.patcher_g = mock.patch('forgeimporters.base.g', mock.MagicMock())
+self.patcher_g.start()
+
+def tearDown(self):
+super(TestTrackerImporter, self).tearDown()
+self.patcher_g.stop()
+
 @mock.patch.object(tracker, 'g')
 @mock.patch.object(tracker, 'c')
 @mock.patch.object(tracker, 'ThreadLocalORMSession')