Source

moin-2.0 / MoinMoin / _tests / test_user.py

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
# -*- coding: utf-8 -*-
# Copyright: 2003-2004 by Juergen Hermann <jh@web.de>
# Copyright: 2009 by ReimarBauer
# License: GNU GPL v2 (or any later version), see LICENSE.txt for details.

"""
    MoinMoin - MoinMoin.user Tests
"""


import pytest

from flask import current_app as app
from flask import g as flaskg

from MoinMoin import user
from MoinMoin.util import crypto


class TestSimple(object):
    def test_create_retrieve(self):
        name = u"foo"
        password = u"barbaz4711"
        email = u"foo@example.org"
        # first create a user
        ret = user.create_user(name, password, email, validate=False)
        assert ret is None, "create_user returned: {0}".format(ret)
        # now try to use it
        u = user.User(name=name, password=password)
        assert u.name == [name]
        assert u.email == email
        assert u.valid


class TestLoginWithPassword(object):
    """user: login tests"""

    def setup_method(self, method):
        # Save original user
        self.saved_user = flaskg.user

        # Create anon user for the tests
        flaskg.user = user.User()

    def teardown_method(self, method):
        """ Run after each test

        Remove user and reset user listing cache.
        """
        # Restore original user
        flaskg.user = self.saved_user

    def testAsciiPassword(self):
        """ user: login with ascii password """
        # Create test user
        name = u'__Non Existent User Name__'
        password = name
        self.createUser(name, password)

        # Try to "login"
        theUser = user.User(name=name, password=password)
        assert theUser.valid

    def testUnicodePassword(self):
        """ user: login with non-ascii password """
        # Create test user
        name = u'__שם משתמש לא קיים__' # Hebrew
        password = name
        self.createUser(name, password)

        # Try to "login"
        theUser = user.User(name=name, password=password)
        assert theUser.valid

    def test_auth_with_ssha_stored_password(self):
        """
        Create user with {SSHA} password and check that user can login.
        """

        # Create test user
        name = u'Test User'
        # pass = 12345
        # salt = salt
        password = '{SSHA}x4YEGdfI4i0qROaY3NTHCmwSJY5zYWx0'
        self.createUser(name, password, True)

        # Try to "login"
        theuser = user.User(name=name, password='12345')
        assert theuser.valid

    def test_auth_with_apr1_stored_password(self):
        """
        Create user with {APR1} password and check that user can login.
        """
        # Create test user
        name = u'Test User'
        # generated with "htpasswd -nbm blaze 12345"
        password = '{APR1}$apr1$NG3VoiU5$PSpHT6tV0ZMKkSZ71E3qg.' # 12345
        self.createUser(name, password, True)

        # Try to "login"
        theuser = user.User(name=name, password='12345')
        assert theuser.valid

    def test_auth_with_md5_stored_password(self):
        """
        Create user with {MD5} password and check that user can login.
        """
        # Create test user
        name = u'Test User'
        password = '{MD5}$1$salt$etVYf53ma13QCiRbQOuRk/' # 12345
        self.createUser(name, password, True)

        # Try to "login"
        theuser = user.User(name=name, password='12345')
        assert theuser.valid

    def test_auth_with_des_stored_password(self):
        """
        Create user with {DES} password and check that user can login.
        """
        # Create test user
        name = u'Test User'
        # generated with "htpasswd -nbd blaze 12345"
        password = '{DES}gArsfn7O5Yqfo' # 12345
        self.createUser(name, password, True)

        try:
            import crypt
            # Try to "login"
            theuser = user.User(name=name, password='12345')
            assert theuser.valid
        except ImportError:
            pytest.skip("Platform does not provide crypt module!")

    def test_auth_with_ssha256_stored_password(self):
        """
        Create user with {SSHA256} password and check that user can login.
        """
        # Create test user
        name = u'Test User'
        # generated with online sha256 tool
        # pass: 12345
        # salt: salt
        # base64 encoded
        password = '{SSHA256}r4ONZUfEyn9MUkcyDQkQ5MBNpdIerM24MasxFpuQBaFzYWx0'

        self.createUser(name, password, True)

        # Try to "login"
        theuser = user.User(name=name, password='12345')
        assert theuser.valid

    def test_regression_user_password_started_with_sha(self):
        # This is regression test for bug in function 'user.create_user'.
        #
        # This function does not encode passwords which start with '{SHA}'
        # It treats them as already encoded SHA hashes.
        #
        # If user during registration specifies password starting with '{SHA}'
        # this password will not get encoded and user object will get saved with empty enc_password
        # field.
        #
        # Such situation leads to "KeyError: 'enc_password'" during
        # user authentication.

        # Any Password begins with the {SHA} symbols led to
        # "KeyError: 'enc_password'" error during user authentication.
        user_name = u'moin'
        user_password = u'{SHA}LKM56'
        user.create_user(user_name, user_password, u'moin@moinmo.in', u'')

        # Try to "login"
        theuser = user.User(name=user_name, password=user_password)
        assert theuser.valid

    def testSubscriptionSubscribedPage(self):
        """ user: tests isSubscribedTo  """
        pagename = u'HelpMiscellaneous'
        name = u'__Jürgen Herman__'
        password = name
        self.createUser(name, password)
        # Login - this should replace the old password in the user file
        theUser = user.User(name=name, password=password)
        theUser.subscribe(pagename)
        assert theUser.isSubscribedTo([pagename]) # list(!) of pages to check

    def testSubscriptionSubPage(self):
        """ user: tests isSubscribedTo on a subpage """
        pagename = u'HelpMiscellaneous'
        testPagename = u'HelpMiscellaneous/FrequentlyAskedQuestions'
        name = u'__Jürgen Herman__'
        password = name
        self.createUser(name, password)
        # Login - this should replace the old password in the user file
        theUser = user.User(name=name, password=password)
        theUser.subscribe(pagename)
        assert not theUser.isSubscribedTo([testPagename]) # list(!) of pages to check

    def test_upgrade_password_from_ssha_to_ssha256(self):
        """
        Create user with {SSHA} password and check that logging in
        upgrades to {SSHA256}.
        """
        name = u'/no such user/'
        #pass = MoinMoin
        #salr = 12345
        password = '{SSHA}xkDIIx1I7A4gC98Vt/+UelIkTDYxMjM0NQ=='
        self.createUser(name, password, True)

        # User is not required to be valid
        theuser = user.User(name=name, password='12345')
        assert theuser.enc_password[:9] == '{SSHA256}'

    def test_upgrade_password_from_sha_to_ssha256(self):
        """
        Create user with {SHA} password and check that logging in
        upgrades to {SSHA256}.
        """
        name = u'/no such user/'
        password = '{SHA}jLIjfQZ5yojbZGTqxg2pY0VROWQ=' # 12345
        self.createUser(name, password, True)

        # User is not required to be valid
        theuser = user.User(name=name, password='12345')
        assert theuser.enc_password[:9] == '{SSHA256}'

    def test_upgrade_password_from_apr1_to_ssha256(self):
        """
        Create user with {APR1} password and check that logging in
        upgrades to {SSHA256}.
        """
        # Create test user
        name = u'Test User'
        # generated with "htpasswd -nbm blaze 12345"
        password = '{APR1}$apr1$NG3VoiU5$PSpHT6tV0ZMKkSZ71E3qg.' # 12345
        self.createUser(name, password, True)

        # User is not required to be valid
        theuser = user.User(name=name, password='12345')
        assert theuser.enc_password[:9] == '{SSHA256}'

    def test_upgrade_password_from_md5_to_ssha256(self):
        """
        Create user with {MD5} password and check that logging in
        upgrades to {SSHA}.
        """
        # Create test user
        name = u'Test User'
        password = '{MD5}$1$salt$etVYf53ma13QCiRbQOuRk/' # 12345
        self.createUser(name, password, True)

        # User is not required to be valid
        theuser = user.User(name=name, password='12345')
        assert theuser.enc_password[:9] == '{SSHA256}'

    def test_upgrade_password_from_des_to_ssha256(self):
        """
        Create user with {DES} password and check that logging in
        upgrades to {SSHA}.
        """
        # Create test user
        name = u'Test User'
        # generated with "htpasswd -nbd blaze 12345"
        password = '{DES}gArsfn7O5Yqfo' # 12345
        self.createUser(name, password, True)

        # User is not required to be valid
        theuser = user.User(name=name, password='12345')
        assert theuser.enc_password[:9] == '{SSHA256}'

    def test_for_email_attribute_by_name(self):
        """
        checks for no access to the email attribute by getting the user object from name
        """
        name = u"__TestUser__"
        password = u"ekfdweurwerh"
        email = u"__TestUser__@moinhost"
        self.createUser(name, password, email=email)
        theuser = user.User(name=name)
        assert theuser.email is None

    # Bookmarks -------------------------------------------------------

    def test_bookmark(self):
        name = u'Test_User_quicklink'
        password = name
        self.createUser(name, password)
        theUser = user.User(name=name, password=password)

        theUser.setBookmark(7)
        result_added = theUser.getBookmark()
        expected = 7
        assert result_added == expected
        # delete the bookmark
        result_success = theUser.delBookmark()
        assert result_success == 0
        result_deleted = theUser.getBookmark()
        assert not result_deleted

        # delBookmark should return 1 on failure
        result_failure = theUser.delBookmark()
        assert result_failure == 1

    # Quicklinks ------------------------------------------------------

    def test_quicklinks(self):
        """
        Test for the quicklinks
        """
        pagename = u'Test_page_quicklink'
        name = u'Test_User_quicklink'
        password = name
        self.createUser(name, password)
        theUser = user.User(name=name, password=password)
        theUser.subscribe(pagename)

        # no quick links exist yet
        result_before = theUser.getQuickLinks()
        assert result_before == []

        result = theUser.isQuickLinkedTo([pagename])
        assert not result

        # quicklinks for the user - theUser exist now
        theUser.quicklinks = [pagename]
        result_after = theUser.getQuickLinks()
        expected = [u'Test_page_quicklink']
        assert result_after == expected

        # test for addQuicklink()
        theUser.addQuicklink(u'Test_page_added')
        result_on_addition = theUser.getQuickLinks()
        expected = [u'Test_page_quicklink', u'MoinTest:Test_page_added']
        assert result_on_addition == expected

        # user should be quicklinked to [pagename]
        result = theUser.isQuickLinkedTo([pagename])
        assert result

        # previously added page u'Test_page_added' is removed
        theUser.removeQuicklink(u'Test_page_added')
        result_on_removal = theUser.getQuickLinks()
        expected = [u'Test_page_quicklink']
        assert result_on_removal == expected

    # Trail -----------------------------------------------------------

    def test_trail(self):
        pagename = u'Test_page_trail'
        name = u'Test_User_trail'
        password = name
        self.createUser(name, password)
        theUser = user.User(name=name, password=password)

        # no item name added to trail
        result = theUser.getTrail()
        expected = []
        assert result == expected

        # item name added to trail
        theUser.addTrail(u'item_added')
        result = theUser.getTrail()
        expected = [u'MoinTest:item_added']
        assert result == expected

    # Other ----------------------------------------------------------

    def test_recovery_token(self):
        name = u'Test_User_other'
        password = name
        self.createUser(name, password)
        theUser = user.User(name=name, password=password)

        # use recovery token to generate new password
        test_token = theUser.generate_recovery_token()
        result_success = theUser.apply_recovery_token(test_token, u'test_newpass')
        assert result_success

        # wrong token
        result_failure = theUser.apply_recovery_token('test_wrong_token', u'test_newpass')
        assert not result_failure

    # Helpers ---------------------------------------------------------

    def createUser(self, name, password, pwencoded=False, email=None, validate=False):
        ret = user.create_user(name, password, email, validate=validate, is_encrypted=pwencoded)
        assert ret is None, "create_user returned: {0}".format(ret)


class TestGroupName(object):

    def testGroupNames(self):
        """ user: isValidName: reject group names """
        test = u'AdminGroup'
        assert not user.isValidName(test)


class TestIsValidName(object):

    def testNonAlnumCharacters(self):
        """ user: isValidName: reject unicode non alpha numeric characters

        : and , used in acl rules, we might add more characters to the syntax.
        """
        invalid = u'! # $ % ^ & * ( ) = + , : ; " | ~ / \\ \u0000 \u202a'.split()
        base = u'User{0}Name'
        for c in invalid:
            name = base.format(c)
            assert not user.isValidName(name)

    def testWhitespace(self):
        """ user: isValidName: reject leading, trailing or multiple whitespace """
        cases = (
            u' User Name',
            u'User Name ',
            u'User   Name',
            )
        for test in cases:
            assert not user.isValidName(test)

    def testValid(self):
        """ user: isValidName: accept names in any language, with spaces """
        cases = (
            u'Jürgen Hermann', # German
            u'ניר סופר', # Hebrew
            u'CamelCase', # Good old camel case
            u'가각간갇갈 갉갊감 갬갯걀갼' # Hangul (gibberish)
            )
        for test in cases:
            assert user.isValidName(test)


coverage_modules = ['MoinMoin.user']