Changeset 346


Ignore:
Timestamp:
06/29/08 10:57:38 (5 years ago)
Author:
dgynn
Message:

updating accountmanagerplugin to  th:rev:3857

Location:
trunk/trac-hacks/accountmanagerplugin/acct_mgr
Files:
8 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/htfile.py

    r56 r346  
    8484                        print userline 
    8585                    matched = True 
    86                 else: 
     86                elif line.endswith('\n'): 
    8787                    print line, 
     88                else: # make sure the last line has a newline 
     89                    print line 
    8890        except EnvironmentError, e: 
    8991            if e.errno == errno.ENOENT: 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/pwhash.py

    r56 r346  
    1717 
    1818from md5crypt import md5crypt 
     19from acct_mgr.util import urandom 
    1920 
    2021class IPasswordHashMethod(Interface): 
     
    6465    crypt = None 
    6566 
    66 # os.urandom was added in Python 2.4 
    67 # try to fall back on reading from /dev/urandom on older Python versions 
    68 try: 
    69     from os import urandom 
    70 except ImportError: 
    71     from random import randrange 
    72     def urandom(n): 
    73         return ''.join([chr(randrange(256)) for _ in xrange(n)]) 
    74  
    7567def salt(): 
    7668    s = '' 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/templates/login.html

    r266 r346  
    2525      </div> 
    2626 
    27       <form method="post" action=""> 
     27      <form method="post" id="acctmgr_loginform" action=""> 
    2828        <input type="hidden" name="referer" value="${referer}" /> 
    2929        <div> 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/templates/prefs_account.html

    r266 r346  
    2020    </div> 
    2121 
    22     <form method="post" action="" 
     22    <form method="post" action="" id="acctmgr_delete_account" 
    2323          onsubmit="return confirm('Are you sure you want to delete your account?');"> 
    2424      <div class="field"> 
     
    4444      <h2>Error</h2> 
    4545      <p>$account.error</p> 
    46     </div> 
    47     <div class="system-message" py:if="account.force_change_passwd"> 
    48       <h2>Immediate action required</h2> 
    49       <p>You are required to change password because of a recent 
    50         password change request.</p> 
    51       <p><strong>Please change your password now.</strong></p> 
    5246    </div> 
    5347    <p py:if="account.message">$account.message</p> 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/templates/register.html

    r266 r346  
    2424      </div> 
    2525 
    26       <form method="post" action=""> 
     26      <form method="post" id="acctmgr_registerform" action=""> 
    2727        <fieldset> 
    2828          <legend>Required</legend> 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/templates/reset_password.html

    r266 r346  
    4141      <p py:if="reset.message">$reset.message</p> 
    4242 
    43       <form method="post" action=""> 
     43      <form method="post" id="acctmgr_passwd_reset" action=""> 
    4444        <div> 
    4545          <label>Username: 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/tests/__init__.py

    r56 r346  
    1212import doctest 
    1313import unittest 
     14try: 
     15    import twill, subprocess 
     16    INCLUDE_FUNCTIONAL_TESTS = True 
     17except ImportError:     
     18    INCLUDE_FUNCTIONAL_TESTS = False 
    1419 
    1520def suite(): 
     
    1823    suite.addTest(htfile.suite()) 
    1924    suite.addTest(db.suite()) 
     25    if INCLUDE_FUNCTIONAL_TESTS: 
     26        from acct_mgr.tests.functional import suite as functional_suite 
     27        suite.addTest(functional_suite()) 
    2028    return suite 
    2129 
    2230if __name__ == '__main__': 
     31    import sys 
     32    if '--skip-functional-tests' in sys.argv: 
     33        sys.argv.remove('--skip-functional-tests') 
     34        INCLUDE_FUNCTIONAL_TESTS = False 
    2335    unittest.main(defaultTest='suite') 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/tests/db.py

    r56 r346  
    2222    def setUp(self): 
    2323        #self.basedir = os.path.realpath(tempfile.mkdtemp()) 
    24         self.env = EnvironmentStub() 
     24        self.env = EnvironmentStub(enable=['trac.*', 'acct_mgr.*']) 
    2525        self.env.config.set('account-manager', 'password_store', 
    2626                            'SessionStore') 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/tests/htfile.py

    r56 r346  
    8686                               'user:$apr1$xW/09...$fb150dT95SoL1HwXtHS/I0') 
    8787 
     88    def test_add_with_no_trailing_newline(self): 
     89        filename = self._create_file('test_add_with_no_trailing_newline', 
     90                                     content='user:$apr1$' 
     91                                             'xW/09...$fb150dT95SoL1HwXtHS/I0') 
     92        self.env.config.set('account-manager', 'password_file', filename) 
     93        self.assertTrue(self.store.check_password('user', 'password')) 
     94        self.store.set_password('user2', 'password2') 
     95        self.assertTrue(self.store.check_password('user', 'password')) 
     96        self.assertTrue(self.store.check_password('user2', 'password2')) 
     97 
    8898 
    8999def suite(): 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/util.py

    r56 r346  
    2323            return path 
    2424        return os.path.normpath(os.path.join(instance.env.path, path)) 
     25 
     26 
     27# os.urandom was added in Python 2.4 
     28# try to fall back on pseudo-random values if it's not available 
     29try: 
     30    from os import urandom 
     31except ImportError: 
     32    from random import randrange 
     33    def urandom(n): 
     34        return ''.join([chr(randrange(256)) for _ in xrange(n)]) 
     35 
     36 
  • trunk/trac-hacks/accountmanagerplugin/acct_mgr/web_ui.py

    r266 r346  
    1010# Author: Matthew Good <trac@matt-good.net> 
    1111 
     12import base64 
     13import os 
    1214import random 
    1315import string 
     
    2123from trac.web.api import IAuthenticator 
    2224from trac.web.main import IRequestHandler, IRequestFilter 
     25from trac.web import chrome 
    2326from trac.web.chrome import INavigationContributor, ITemplateProvider 
    2427from genshi.builder import tag 
    2528 
    2629from api import AccountManager 
     30from acct_mgr.util import urandom 
    2731 
    2832def _create_user(req, env, check_permissions=True): 
     
    7983 
    8084 
    81 class PasswordResetNotification(NotifyEmail): 
    82     template_name = 'reset_password_email.txt' 
     85class SingleUserNofification(NotifyEmail): 
     86    """Helper class used for account email notifications which should only be 
     87    sent to one persion, not including the rest of the normally CCed users 
     88    """ 
    8389    _username = None 
    8490 
     
    95101            return None 
    96102 
    97     def notify(self, username, password): 
     103    def notify(self, username, subject): 
    98104        # save the username for use in `get_smtp_address` 
    99105        self._username = username 
     106        old_public_cc = self.config.getbool('notification', 'use_public_cc') 
     107        # override public cc option so that the user's email is included in the To: field 
     108        self.config.set('notification', 'use_public_cc', 'true') 
     109        try: 
     110            NotifyEmail.notify(self, username, subject) 
     111        finally: 
     112            self.config.set('notification', 'use_public_cc', old_public_cc) 
     113 
     114 
     115class PasswordResetNotification(SingleUserNofification): 
     116    template_name = 'reset_password_email.txt' 
     117 
     118    def notify(self, username, password): 
    100119        self.data.update({ 
    101120            'account': { 
     
    111130        subject = '[%s] Trac password reset for user: %s' % (projname, username) 
    112131 
    113         NotifyEmail.notify(self, username, subject) 
     132        SingleUserNofification.notify(self, username, subject) 
    114133 
    115134 
     
    195214        data = {'delete_enabled': delete_enabled} 
    196215        force_change_password = req.session.get('force_change_passwd', False) 
    197         if force_change_password: 
    198             data['force_change_passwd'] = True 
    199216        if req.method == 'POST': 
    200217            if action == 'save': 
    201218                data.update(self._do_change_password(req)) 
    202219                if force_change_password: 
    203                     data['force_change_passwd'] = False 
    204220                    del(req.session['force_change_passwd']) 
    205221                    req.session.save() 
     222                    chrome.add_notice(req, MessageWrapper(tag( 
     223                        "Thank you for taking the time to update your password." 
     224                    ))) 
     225                    force_change_password = False 
    206226            elif action == 'delete' and delete_enabled: 
    207227                data.update(self._do_delete(req)) 
    208228            else: 
    209229                data.update({'error': 'Invalid action'}) 
     230        if force_change_password: 
     231            chrome.add_warning(req, MessageWrapper(tag( 
     232                "You are required to change password because of a recent " 
     233                "password change request. ", 
     234                tag.b("Please change your password now.")))) 
    210235        return data 
    211236 
     
    453478        return [resource_filename(__name__, 'templates')] 
    454479 
     480 
     481class MessageWrapper(object): 
     482    """Wrapper for add_warning and add_notice to work around the requirement 
     483    for a % operator.""" 
     484    def __init__(self, body): 
     485        self.body = body 
     486 
     487    def __mod__(self, rhs): 
     488        return self.body 
     489 
     490 
     491class EmailVerificationNotification(SingleUserNofification): 
     492    template_name = 'verify_email.txt' 
     493 
     494    def notify(self, username, token): 
     495        self.data.update({ 
     496            'account': { 
     497                'username': username, 
     498                'token': token, 
     499            }, 
     500            'verify': { 
     501                'link': self.env.abs_href.verify_email(token=token), 
     502            } 
     503        }) 
     504 
     505        projname = self.config.get('project', 'name') 
     506        subject = '[%s] Trac email verification for user: %s' % (projname, username) 
     507 
     508        SingleUserNofification.notify(self, username, subject) 
     509 
     510 
     511class EmailVerificationModule(Component): 
     512    implements(IRequestFilter, IRequestHandler) 
     513 
     514    # IRequestFilter methods 
     515 
     516    def pre_process_request(self, req, handler): 
     517        if not req.session.authenticated: 
     518            # Anonymous users should register and perms should be tweaked so 
     519            # that anonymous users can't edit wiki pages and change or create 
     520            # tickets. As such, this email verifying code won't be used on them 
     521            return handler 
     522        if handler is not self and 'email_verification_token' in req.session: 
     523            chrome.add_warning(req, MessageWrapper(tag.span( 
     524                    'Your permissions have been limited until you ', 
     525                    tag.a(href=req.href.verify_email())( 
     526                          'verify your email address')))) 
     527            req.perm = perm.PermissionCache(self.env, 'anonymous') 
     528        return handler 
     529 
     530    def post_process_request(self, req, template, data, content_type): 
     531        if not req.session.authenticated: 
     532            # Anonymous users should register and perms should be tweaked so 
     533            # that anonymous users can't edit wiki pages and change or create 
     534            # tickets. As such, this email verifying code won't be used on them 
     535            return template, data, content_type 
     536        if req.session.get('email') != req.session.get('email_verification_sent_to'): 
     537            req.session['email_verification_token'] = self._gen_token() 
     538            req.session['email_verification_sent_to'] = req.session.get('email') 
     539            self._send_email(req) 
     540            chrome.add_notice(req, MessageWrapper(tag.span( 
     541                    'An email has been sent to ', req.session['email'], 
     542                    ' with a token to ', 
     543                    tag.a(href=req.href.verify_email())( 
     544                        'verify your new email address')))) 
     545        return template, data, content_type 
     546 
     547    # IRequestHandler methods 
     548 
     549    def match_request(self, req): 
     550        return req.path_info == '/verify_email' 
     551 
     552    def process_request(self, req): 
     553        if 'email_verification_token' not in req.session: 
     554            chrome.add_notice(req, 'Your email is already verified') 
     555        elif req.method != 'POST': 
     556            pass 
     557        elif 'resend' in req.args: 
     558            self._send_email(req) 
     559            chrome.add_notice(req, 
     560                    'A notification email has been resent to %s.', 
     561                    req.session.get('email')) 
     562        elif 'verify' in req.args: 
     563            if req.args['token'] == req.session['email_verification_token']: 
     564                del req.session['email_verification_token'] 
     565                chrome.add_notice(req, 'Thank you for verifying your email address') 
     566            else: 
     567                chrome.add_warning(req, 'Invalid verification token') 
     568        data = {} 
     569        if 'token' in req.args: 
     570            data['token'] = req.args['token'] 
     571        return 'verify_email.html', data, None 
     572 
     573    def _gen_token(self): 
     574        return base64.urlsafe_b64encode(urandom(6)) 
     575 
     576    def _send_email(self, req): 
     577        notifier = EmailVerificationNotification(self.env) 
     578        notifier.notify(req.authname, req.session['email_verification_token']) 
Note: See TracChangeset for help on using the changeset viewer.