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/20 17:52:21 UTC

[04/15] git commit: [#7432] ticket:598 Auth provider methods for pwd expiration support

[#7432] ticket:598 Auth provider methods for pwd expiration support


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

Branch: refs/heads/master
Commit: 899e1444266e9523e4b329e54444a3c9cdb7420d
Parents: 899d182
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Jun 4 16:10:21 2014 +0300
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Jun 20 15:39:17 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/plugin.py                    | 27 ++++++++++
 Allura/allura/model/auth.py                    |  1 +
 Allura/allura/tests/model/test_auth.py         | 51 ++++++++++++++----
 Allura/allura/tests/unit/test_auth_provider.py | 60 +++++++++++++++++++++
 4 files changed, 130 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/899e1444/Allura/allura/lib/plugin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/plugin.py b/Allura/allura/lib/plugin.py
index ffe9d29..f9467be 100644
--- a/Allura/allura/lib/plugin.py
+++ b/Allura/allura/lib/plugin.py
@@ -229,6 +229,26 @@ class AuthenticationProvider(object):
         '''
         raise NotImplementedError, 'user_registration_date'
 
+    def get_last_password_updated(self, user):
+        '''
+        Returns the date when the user updated password for a last time.
+
+        :param user: a :class:`User <allura.model.auth.User>`
+        :rtype: :class:`datetime <datetime.datetime>`
+        '''
+        raise NotImplementedError, 'get_last_password_updated'
+
+    def is_password_expired(self, user):
+        days = asint(config.get('auth.pwdexpire.days', 0))
+        before = asint(config.get('auth.pwdexpire.before', 0))
+        now = datetime.utcnow()
+        last_updated = self.get_last_password_updated(user)
+        if days and now - last_updated > timedelta(days=days):
+            return True
+        if before and last_updated < datetime.fromtimestamp(before):
+            return True
+        return False
+
 
 class LocalAuthenticationProvider(AuthenticationProvider):
 
@@ -280,6 +300,7 @@ class LocalAuthenticationProvider(AuthenticationProvider):
 
     def set_password(self, user, old_password, new_password):
         user.password = self._encode_password(new_password)
+        user.last_password_updated = datetime.utcnow()
 
     def _encode_password(self, password, salt=None):
         from allura import model as M
@@ -304,6 +325,12 @@ class LocalAuthenticationProvider(AuthenticationProvider):
             return user._id.generation_time
         return datetime.utcnow()
 
+    def get_last_password_updated(self, user):
+        d = user.last_password_updated
+        if d is None:
+            return self.user_registration_date(user)
+        return d
+
 
 def ldap_conn(who=None, cred=None):
     '''

http://git-wip-us.apache.org/repos/asf/allura/blob/899e1444/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 17f1175..c7b1004 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -226,6 +226,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
     username = FieldProperty(str)
     email_addresses = FieldProperty([str])
     password = FieldProperty(str)
+    last_password_updated = FieldProperty(datetime)
     projects = FieldProperty(S.Deprecated)
     # full mount point: prefs dict
     tool_preferences = FieldProperty({str: {str: None}})

http://git-wip-us.apache.org/repos/asf/allura/blob/899e1444/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 35f056e..49dc839 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -20,12 +20,19 @@
 """
 Model tests for auth
 """
-from nose.tools import with_setup, assert_equal, assert_not_in, assert_in
+from nose.tools import (
+    with_setup,
+    assert_equal,
+    assert_not_in,
+    assert_in,
+    assert_true,
+)
 from pylons import tmpl_context as c, app_globals as g
 from webob import Request
-from mock import patch
+from mock import patch, Mock
 from datetime import datetime, timedelta
 
+from bson import ObjectId
 from pymongo.errors import DuplicateKeyError
 from ming.orm.ormsession import ThreadLocalORMSession
 
@@ -41,13 +48,39 @@ def setUp():
     setup_global_objects()
 
 
-@with_setup(setUp)
-def test_password_encoder():
-    # Verify salt
-    ep = plugin.LocalAuthenticationProvider(
-        Request.blank('/'))._encode_password
-    assert ep('test_pass') != ep('test_pass')
-    assert ep('test_pass', '0000') == ep('test_pass', '0000')
+class TestLocalAuthenticationProvider(object):
+
+    def setUp(self):
+        setUp()
+        self.provider = plugin.LocalAuthenticationProvider(Request.blank('/'))
+
+    def test_password_encoder(self):
+        # Verify salt
+        ep = self.provider._encode_password
+        assert ep('test_pass') != ep('test_pass')
+        assert ep('test_pass', '0000') == ep('test_pass', '0000')
+
+    def test_set_password_sets_last_updated(self):
+        user = Mock()
+        user.last_password_updated = None
+        now1 = datetime.utcnow()
+        self.provider.set_password(user, '', '')
+        now2 = datetime.utcnow()
+        assert_true(user.last_password_updated > now1)
+        assert_true(user.last_password_updated < now2)
+
+    def test_get_last_password_updated_not_set(self):
+        user = Mock()
+        user._id = ObjectId()
+        user.last_password_updated = None
+        upd = self.provider.get_last_password_updated(user)
+        assert_equal(upd, user._id.generation_time)
+
+    def test_get_last_password_updated(self):
+        user = Mock()
+        user.last_password_updated = datetime(2014, 06, 04, 13, 13, 13)
+        upd = self.provider.get_last_password_updated(user)
+        assert_equal(upd, user.last_password_updated)
 
 
 @with_setup(setUp)

http://git-wip-us.apache.org/repos/asf/allura/blob/899e1444/Allura/allura/tests/unit/test_auth_provider.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_auth_provider.py b/Allura/allura/tests/unit/test_auth_provider.py
new file mode 100644
index 0000000..2ecd109
--- /dev/null
+++ b/Allura/allura/tests/unit/test_auth_provider.py
@@ -0,0 +1,60 @@
+# -*- 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.
+
+import datetime as dt
+import calendar
+
+import tg
+from mock import Mock
+from nose.tools import assert_true, assert_false
+from webob import Request
+
+from alluratest.controller import setup_basic_test
+from allura.lib import plugin
+from allura.lib import helpers as h
+
+
+class TestAuthenticationProvider(object):
+
+    def setUp(self):
+        setup_basic_test()
+        self.provider = plugin.AuthenticationProvider(Request.blank('/'))
+        self.pwd_updated = dt.datetime.utcnow() - dt.timedelta(days=100)
+        self.provider.get_last_password_updated = lambda u: self.pwd_updated
+        self.user = Mock()
+
+    def test_is_password_expired_disabled(self):
+        assert_false(self.provider.is_password_expired(self.user))
+
+    def test_is_password_expired_days(self):
+        with h.push_config(tg.config, **{'auth.pwdexpire.days': '180'}):
+            assert_false(self.provider.is_password_expired(self.user))
+        with h.push_config(tg.config, **{'auth.pwdexpire.days': '90'}):
+            assert_true(self.provider.is_password_expired(self.user))
+
+    def test_is_password_expired_before(self):
+        before = dt.datetime.utcnow() - dt.timedelta(days=180)
+        before = calendar.timegm(before.timetuple())
+        with h.push_config(tg.config, **{'auth.pwdexpire.before': str(before)}):
+            assert_false(self.provider.is_password_expired(self.user))
+
+        before = dt.datetime.utcnow() - dt.timedelta(days=1)
+        before = calendar.timegm(before.timetuple())
+        with h.push_config(tg.config, **{'auth.pwdexpire.before': str(before)}):
+            assert_true(self.provider.is_password_expired(self.user))