PK©e6acct_mgr/__init__.pyPK}68.À¸É.*.*acct_mgr/htfile.pyc;ò *ÍìEc@sDdklZdklZdkZdkZdkZdkZdk Z dk l Z dk Tdk l Z dklZydklZWnej o eZnXydklZWn)ej od klZd „ZnXd e fd „ƒYZd efd„ƒYZd„Zdefd„ƒYZdefd„ƒYZdS((s generators(shexlifyN(smd5crypt(s*(sOption(sIPasswordStore(scrypt(surandom(s randrangecCsDdigi}t|ƒD]}|ttdƒƒƒq~ƒSdS(Nsi(sjoinsappends_[1]sxrangesns_schrs randrange(sns_[1]s_((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pysurandom(ss_RelativePathOptioncBstZd„ZRS(NcCsY|tjo|Sntt|ƒi||ƒ}tii tii |i i|ƒƒSdS(N( sinstancesNonesselfssupers_RelativePathOptions__get__sownerspathsossnormpathsjoinsenv(sselfsinstancesownerspath((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys__get__.s (s__name__s __module__s__get__(((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys_RelativePathOption,ssAbstractPasswordFileStorecBsStZdZeddƒZd„Zd„Zd„Zd„Zd„Z d„Z RS( s˜Base class for managing password files such as Apache's htpasswd and htdigest formats. See the concrete sub-classes for usage information. saccount-managers password_filecCs||iƒjSdS(N(susersselfs get_users(sselfsuser((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pyshas_user>scCs6|i}tii|ƒ ogSn|i|ƒSdS(N(sselfsfilenamesosspathsexistss _get_users(sselfsfilename((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys get_usersAs cCsH|idƒ}|idƒ}|i|i|ƒ|i||ƒƒ SdS(Nsutf-8(susersencodespasswordsselfs _update_filesprefixsuserline(sselfsuserspassword((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys set_passwordGscCs,|idƒ}|i|i|ƒtƒSdS(Nsutf-8(susersencodesselfs _update_filesprefixsNone(sselfsuser((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys delete_userMscCs·|i}tii|ƒ otSn|i|idƒƒ}|idƒ}t |ƒ}zIxB|D]:}|i |ƒo$|i|||t|ƒd!ƒSqbqbWWd|iƒXtSdS(Nsutf-8iÿÿÿÿ(sselfsfilenamesosspathsexistssFalsesprefixsusersencodespasswordsfilesfdslines startswiths_check_userlineslensclose(sselfsuserspasswordsfilenamesprefixsfdsline((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pyscheck_passwordQs     cCs |i}t}y`xYtit|ƒdtƒD]<}|i |ƒo"| o|o |GHnt}q.|Gq.WWnRt j oF}|itijoqÄ|itijotdƒ‚qÄ‚nX| o|o/t|dƒ}z||IJWd|iƒXn|SdS(saIf `userline` is empty the line starting with `prefix` is removed from the user file. Otherwise the line starting with `prefix` is updated to `userline`. If no line starts with `prefix` the `userline` is appended to the file. Returns `True` if a line matching `prefix` was updated, `False` otherwise. sinplaces€The password file could not be updated. Trac requires read and write access to both the password file and its parent directory.saN(sselfsfilenamesFalsesmatcheds fileinputsinputsstrsTrueslines startswithsprefixsuserlinesEnvironmentErrorseserrnosENOENTsEACCESs TracErrorsopensfsclose(sselfsprefixsuserlinesfsfilenameseslinesmatched((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys _update_fileas0    ( s__name__s __module__s__doc__s_RelativePathOptionsfilenameshas_users get_userss set_passwords delete_userscheck_passwords _update_file(((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pysAbstractPasswordFileStore5s      cCsbd}tttdƒƒdƒ}d}x0tdƒD]"}|||d@7}|dL}q4W|SdS(Nsiis@./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzii?i(ssslongshexlifysurandomsvsitoa64srangesi(sisvsssitoa64((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pyssalt†s  s HtPasswdStorecBsEtZdZeeƒd„Zd„Zd„Zd„Zd„Z RS(s Manages user accounts stored in Apache's htpasswd format. To use this implementation add the following configuration section to trac.ini: {{{ [account-manager] password_store = HtPasswdStore password_file = /path/to/trac.htpasswd }}} cCsdSdS(Nshtpasswd((sself((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys config_keyscCs |dSdS(Ns:(suser(sselfsuser((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pysprefix scCsRttjo$|i|ƒt|tƒdƒSn|i|ƒt|tƒƒSdS(Ns$apr1$(scryptsNonesselfsprefixsusersmd5cryptspasswordssalt(sselfsuserspassword((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pysuserline£s $cCs­|idƒo+|t||didƒddƒjSno|idƒo.|dti|ƒiƒidƒd jSn1t t jot d ƒ‚n|t ||ƒjSdS( Ns$apr1$is$is{SHA}isbase64iÿÿÿÿs„The "crypt" module is unavailable on this platform. Only MD5 passwords (starting with "$apr1$") are supported in the htpasswd file.( ssuffixs startswithsmd5cryptspasswordssplitsshasnewsdigestsencodescryptsNonesNotImplementedError(sselfspasswordsprefixssuffix((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys_check_userline©s. ccsOt|ƒ}x<|D]4}|iddƒd}|o|idƒVqqWdS(Ns:iisutf-8(sopensfilenamesfslinessplitsusersdecode(sselfsfilenamesfsusersline((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys _get_users¹s  ( s__name__s __module__s__doc__s implementssIPasswordStores config_keysprefixsuserlines_check_userlines _get_users(((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys HtPasswdStores      s HtDigestStorecBsTtZdZeeƒeddƒZd„Zd„Zd„Z d„Z d„Z RS(s0Manages user accounts stored in Apache's htdigest format. To use this implementation add the following configuration section to trac.ini: {{{ [account-manager] password_store = HtDigestStore password_file = /path/to/trac.htdigest htdigest_realm = TracDigestRealm }}} saccount-managershtdigest_realmcCsdSdS(Nshtdigest((sself((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys config_keyÓscCsd||ifSdS(Ns%s:%s:(susersselfsrealm(sselfsuser((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pysprefixÖscCs.|i|ƒ}|ti||ƒiƒSdS(N(sselfsprefixsuserspsmd5snewspasswords hexdigest(sselfsuserspasswordsp((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pysuserlineÙscCs!|ti||ƒiƒjSdS(N(ssuffixsmd5snewsprefixspasswords hexdigest(sselfspasswordsprefixssuffix((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys_check_userlineÝsccs…|i}t|ƒ}xi|D]a}|idƒd }t |ƒdjo5|\}}||jo|o|i dƒVq}qqWdS(Ns:isutf-8( sselfsrealms_realmsopensfilenamesfslinessplitsargsslensusersdecode(sselfsfilenamesrealmsfsargssuserslines_realm((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys _get_usersàs   ( s__name__s __module__s__doc__s implementssIPasswordStoresOptionsrealms config_keysprefixsuserlines_check_userlines _get_users(((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys HtDigestStoreÁs      (s __future__s generatorssbinasciishexlifyserrnosmd5sshasos.pathsoss fileinputsmd5crypts trac.cores trac.configsOptionsapisIPasswordStorescrypts ImportErrorsNonesurandomsrandoms randranges_RelativePathOptions ComponentsAbstractPasswordFileStoressalts HtPasswdStores HtDigestStore(s HtPasswdStoresAbstractPasswordFileStoresOptionsIPasswordStoreserrnos_RelativePathOptionscrypts randrangessaltsmd5cryptsshas generatorsshexlifys fileinputsurandoms HtDigestStoresossmd5((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/htfile.pys? s.           Q 2PK‚}68iü)îJQJQacct_mgr/web_ui.pyc;ò *ÍìEc@s!dklZdkZdkZdklZlZdkTdkl Z dk l Z l Z dk lZdklZdklZd klZlZd klZd klZed „Zd e fd„ƒYZdefd„ƒYZdefd„ƒYZd„Z dei!fd„ƒYZ!dS((s generatorsN(spermsutil(s*(s IntOption(sNotificationSystems NotifyEmail(sauth(sIAuthenticator(sIRequestHandler(sINavigationContributorsITemplateProvider(sMarkup(sAccountManagerc Csât|ƒ}|iidƒ} | otdƒ‚n|i| ƒotdƒ‚n|oBt i |ƒ} | i | ƒ| i dƒjotdƒ‚qŸn|iidƒ} | otdƒ‚n| |iidƒjotdƒ‚n|i| | ƒ|iƒ}|iƒ}|id | fƒ|iƒ\}| o|id | fƒnxvd d fD]h}|ii|ƒ}| oqhn|id ||| fƒ|i o|id| ||fƒqhqhW|iƒdS(NsusersUsername cannot be empty.s.Another account with that name already exists.s authenticatedspasswordsPassword cannot be empty.spassword_confirmsThe passwords must match.s=SELECT count(*) FROM session WHERE sid=%s AND authenticated=1sFINSERT INTO session (sid, authenticated, last_visit) VALUES (%s, 1, 0)snamesemailsRUPDATE session_attribute SET value=%s WHERE name=%s AND sid=%s AND authenticated=1sPINSERT INTO session_attribute (sid,authenticated,name,value) VALUES (%s,1,%s,%s)(sAccountManagersenvsmgrsreqsargssgetsusers TracErrorshas_userscheck_permissionsspermsPermissionSystemspermission_systemsget_user_permissionsspasswords set_passwords get_db_cnxsdbscursorsexecutesfetchonesexistsskeysvaluesrowcountscommit( sreqsenvscheck_permissionssvalueskeysexistssdbscursorsmgrspermission_systemsuserspassword((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pys _create_usersF          sPasswordResetNotificationcBs/tZdZeZd„Zd„Zd„ZRS(Nsreset_password_email.cscCs|ggfSdS(N(sresid(sselfsresid((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysget_recipientsVscCs,||ijoti||ƒSntSdS(s€Overrides `get_smtp_address` in order to prevent CCing users other than the user whose password is being reset. N(saddrsselfs _usernames NotifyEmailsget_smtp_addresssNone(sselfsaddr((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysget_smtp_addressYscCsx||_||id<||id<|iiiƒ|id<|ii ddƒ}d||f}t i |||ƒdS(Nsaccount.usernamesaccount.passwords login.linksprojectsnames%[%s] Trac password reset for user: %s(susernamesselfs _usernameshdfspasswordsenvsabs_hrefsloginsconfigsgetsprojnamessubjects NotifyEmailsnotify(sselfsusernamespasswordsprojnamessubject((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysnotifybs   (s__name__s __module__s template_namesNones _usernamesget_recipientssget_smtp_addresssnotify(((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysPasswordResetNotificationRs   s AccountModulecBs»tZdZeeeeƒeiei Z e ddddƒZ d„Z ed„Zd„Zd„Zd „Zd „Zd „Zd „Zd „Zd„Zd„Zd„Zd„ZRS(sÔAllows users to change their password, reset their password if they've forgotten it, or delete their account. The settings for the AccountManager module must be set in trac.ini in order to use this. saccount-managersgenerated_password_lengthis^Length of the randomly-generated passwords created when resetting the password for an account.cCs|idtƒdS(Nslog(sselfs _write_checksTrue(sself((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pys__init__}scCsCt|iƒidƒ}| o|o|iidƒn|SdS(Ns set_passwordsNAccountModule is disabled because the password store does not support writing.(sAccountManagersselfsenvssupportsswritableslogswarn(sselfslogswritable((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pys _write_check€scCsdSdS(Nsaccount((sselfsreq((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysget_active_navigation_itemˆsccsM|iƒ odSn|idjo#ddtd|iiƒƒfVndS(Ns anonymoussmetanavsaccountsMy Account(sselfs _write_checksreqsauthnamesMarkupshrefsaccount(sselfsreq((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysget_navigation_items‹s  cCs*|iddfjo|idtƒSdS(Ns/accounts/reset_passwordslog(sreqs path_infosselfs _write_checksTrue(sselfsreq((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pys match_request“scCsZ|idjo|i|ƒdtfSn,|idjo|i|ƒdtfSndS(Ns/accounts account.css/reset_passwordsreset_password.cs(sreqs path_infosselfs _do_accountsNones_do_reset_password(sselfsreq((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysprocess_request—s   cCs¸|idjo|i|iiiƒƒn|iidƒ}t |iƒi dƒ}||i d<|idjo@|djo|i|ƒq´|djo|i|ƒq´ndS(Ns anonymoussactions delete_usersdelete_enabledsPOSTschange_passwordsdelete(sreqsauthnamesredirectsselfsenvshrefswikisargssgetsactionsAccountManagerssupportssdelete_enabledshdfsmethods_do_change_passwords _do_delete(sselfsreqsactionsdelete_enabled((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pys _do_accountŸs   cCs0|idjo+t|id<|iiƒ|idRegister(sselfs _enable_checksreqsauthnamesMarkupsenvshrefsregister(sselfsreq((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pysget_navigation_itemss  cCs$|idjo|idtƒSdS(Ns /registerslog(sreqs path_infosselfs _enable_checksTrue(sselfsreq((s3build/bdist.darwin-8.0.1-x86/egg/acct_mgr/web_ui.pys match_request%scCsï|idjo|i|iiiƒƒn|iidƒ}|i djo |djoYyt ||iƒWn%t j o}|i|id # # "THE BEER-WARE LICENSE" (Revision 42): # wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return. Matthew Good # # Author: Matthew Good from trac.core import * from trac.config import Option, ExtensionOption class IPasswordStore(Interface): """An interface for Components that provide a storage method for users and passwords. """ def config_key(self): """ '''Deprecated''': new implementations of this interface are not required to implement this method, since the prefered way to configure the `IPasswordStore` implemenation is by using its class name in the `password_store` option. Returns a string used to identify this implementation in the config. This password storage implementation will be used if the value of the config property "account-manager.password_format" matches. """ def get_users(self): """Returns an iterable of the known usernames """ def has_user(self, user): """Returns whether the user account exists. """ def set_password(self, user, password): """Sets the password for the user. This should create the user account if it doesn't already exist. Returns True if a new account was created, False if an existing account was updated. """ def check_password(self, user, password): """Checks if the password is valid for the user. """ def delete_user(self, user): """Deletes the user account. Returns True if the account existed and was deleted, False otherwise. """ class IAccountChangeListener(Interface): """An interface for receiving account change events. """ def user_created(self, user, password): """New user """ def user_password_changed(self, user, password): """Password changed """ def user_deleted(self, user): """User deleted """ class AccountManager(Component): """The AccountManager component handles all user account management methods provided by the IPasswordStore interface. The methods will be handled by the underlying password storage implementation set in trac.ini with the "account-manager.password_format" setting. """ implements(IAccountChangeListener) _password_store = ExtensionOption('account-manager', 'password_store', IPasswordStore) _password_format = Option('account-manager', 'password_format') stores = ExtensionPoint(IPasswordStore) change_listeners = ExtensionPoint(IAccountChangeListener) # Public API def get_users(self): return self.password_store.get_users() def has_user(self, user): return self.password_store.has_user(user) def set_password(self, user, password): if self.password_store.set_password(user, password): self._notify('created', user, password) else: self._notify('password_changed', user, password) def check_password(self, user, password): return self.password_store.check_password(user, password) def delete_user(self, user): if self.password_store.delete_user(user): self._notify('deleted', user) def supports(self, operation): try: store = self.password_store except AttributeError: return False else: return hasattr(store, operation) def password_store(self): try: return self._password_store except AttributeError: # fall back on old "password_format" option fmt = self._password_format for store in self.stores: config_key = getattr(store, 'config_key', None) if config_key is None: continue if config_key() == fmt: return store # if the "password_format" is not set re-raise the AttributeError raise password_store = property(password_store) def _notify(self, func, *args): func = 'user_' + func for l in self.change_listeners: getattr(l, func)(*args) # IAccountChangeListener methods def user_created(self, user, password): self.log.info('Created new user: %s' % user) def user_password_changed(self, user, password): self.log.info('Updated password for user: %s' % user) def user_deleted(self, user): self.log.info('Deleted user: %s' % user) PK©e6‘ÈXnnacct_mgr/http.py# -*- coding: utf8 -*- # # Copyright (C) 2005 Matthew Good # # "THE BEER-WARE LICENSE" (Revision 42): # wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return. Matthew Good # # Author: Matthew Good from urllib2 import build_opener, HTTPBasicAuthHandler, \ HTTPDigestAuthHandler, HTTPPasswordMgrWithDefaultRealm from trac.core import * from trac.config import Option from api import IPasswordStore class HttpAuthStore(Component): implements(IPasswordStore) auth_url = Option('account-manager', 'authentication_url') def check_password(self, user, password): mgr = HTTPPasswordMgrWithDefaultRealm() mgr.add_password(None, self.auth_url, user, password) try: build_opener(HTTPBasicAuthHandler(mgr), HTTPDigestAuthHandler(mgr)).open(self.auth_url) except IOError: return False else: return True PK©e6”Q«aÊÊacct_mgr/htfile.py# -*- coding: utf8 -*- # # Copyright (C) 2005 Matthew Good # # "THE BEER-WARE LICENSE" (Revision 42): # wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return. Matthew Good # # Author: Matthew Good from __future__ import generators from binascii import hexlify import errno import md5, sha import os.path import fileinput from md5crypt import md5crypt from trac.core import * from trac.config import Option from api import IPasswordStore # check for the availability of the "crypt" module for checking passwords on # Unix-like platforms # MD5 is still used when adding/updating passwords try: from crypt import crypt except ImportError: crypt = None # os.urandom was added in Python 2.4 # try to fall back on reading from /dev/urandom on older Python versions try: from os import urandom except ImportError: from random import randrange def urandom(n): return ''.join([chr(randrange(256)) for _ in xrange(n)]) class _RelativePathOption(Option): def __get__(self, instance, owner): if instance is None: return self path = super(_RelativePathOption, self).__get__(instance, owner) return os.path.normpath(os.path.join(instance.env.path, path)) class AbstractPasswordFileStore(Component): """Base class for managing password files such as Apache's htpasswd and htdigest formats. See the concrete sub-classes for usage information. """ filename = _RelativePathOption('account-manager', 'password_file') def has_user(self, user): return user in self.get_users() def get_users(self): filename = self.filename if not os.path.exists(filename): return [] return self._get_users(filename) def set_password(self, user, password): user = user.encode('utf-8') password = password.encode('utf-8') return not self._update_file(self.prefix(user), self.userline(user, password)) def delete_user(self, user): user = user.encode('utf-8') return self._update_file(self.prefix(user), None) def check_password(self, user, password): filename = self.filename if not os.path.exists(filename): return False prefix = self.prefix(user.encode('utf-8')) password = password.encode('utf-8') fd = file(filename) try: for line in fd: if line.startswith(prefix): return self._check_userline(password, prefix, line[len(prefix):-1]) finally: fd.close() return False def _update_file(self, prefix, userline): """If `userline` is empty the line starting with `prefix` is removed from the user file. Otherwise the line starting with `prefix` is updated to `userline`. If no line starts with `prefix` the `userline` is appended to the file. Returns `True` if a line matching `prefix` was updated, `False` otherwise. """ filename = self.filename matched = False try: for line in fileinput.input(str(filename), inplace=True): if line.startswith(prefix): if not matched and userline: print userline matched = True else: print line, except EnvironmentError, e: if e.errno == errno.ENOENT: pass # ignore when file doesn't exist and create it below elif e.errno == errno.EACCES: raise TracError('The password file could not be updated. ' 'Trac requires read and write access to both ' 'the password file and its parent directory.') else: raise if not matched and userline: f = open(filename, 'a') try: print >>f, userline finally: f.close() return matched def salt(): s = '' v = long(hexlify(urandom(4)), 16) itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' for i in range(8): s += itoa64[v & 0x3f]; v >>= 6 return s class HtPasswdStore(AbstractPasswordFileStore): """Manages user accounts stored in Apache's htpasswd format. To use this implementation add the following configuration section to trac.ini: {{{ [account-manager] password_store = HtPasswdStore password_file = /path/to/trac.htpasswd }}} """ implements(IPasswordStore) def config_key(self): return 'htpasswd' def prefix(self, user): return user + ':' def userline(self, user, password): if crypt is None: return self.prefix(user) + md5crypt(password, salt(), '$apr1$') else: return self.prefix(user) + crypt(password, salt()) def _check_userline(self, password, prefix, suffix): if suffix.startswith('$apr1$'): return suffix == md5crypt(password, suffix[6:].split('$')[0], '$apr1$') elif suffix.startswith('{SHA}'): return (suffix[5:] == sha.new(password).digest().encode('base64')[:-1]) elif crypt is None: # crypt passwords are only supported on Unix-like systems raise NotImplementedError('The "crypt" module is unavailable ' 'on this platform. Only MD5 ' 'passwords (starting with "$apr1$") ' 'are supported in the htpasswd file.') else: return suffix == crypt(password, suffix) def _get_users(self, filename): f = open(filename) for line in f: user = line.split(':', 1)[0] if user: yield user.decode('utf-8') class HtDigestStore(AbstractPasswordFileStore): """Manages user accounts stored in Apache's htdigest format. To use this implementation add the following configuration section to trac.ini: {{{ [account-manager] password_store = HtDigestStore password_file = /path/to/trac.htdigest htdigest_realm = TracDigestRealm }}} """ implements(IPasswordStore) realm = Option('account-manager', 'htdigest_realm') def config_key(self): return 'htdigest' def prefix(self, user): return '%s:%s:' % (user, self.realm) def userline(self, user, password): p = self.prefix(user) return p + md5.new(p + password).hexdigest() def _check_userline(self, password, prefix, suffix): return suffix == md5.new(prefix + password).hexdigest() def _get_users(self, filename): _realm = self.realm f = open(filename) for line in f: args = line.split(':')[:2] if len(args) == 2: user, realm = args if realm == _realm and user: yield user.decode('utf-8') PK©e6ê♼ acct_mgr/md5crypt.py# -*- coding: utf-8 -*- # # Based on FreeBSD src/lib/libcrypt/crypt.c 1.2 # http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libcrypt/crypt.c?rev=1.2&content-type=text/plain # Original license: # * "THE BEER-WARE LICENSE" (Revision 42): # * wrote this file. As long as you retain this notice you # * can do whatever you want with this stuff. If we meet some day, and you think # * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp # This port adds no further stipulations. I forfeit any copyright interest. import md5 def md5crypt(password, salt, magic='$1$'): # /* The password first, since that is what is most unknown */ /* Then our magic string */ /* Then the raw salt */ m = md5.new() m.update(password + magic + salt) # /* Then just as many characters of the MD5(pw,salt,pw) */ mixin = md5.md5(password + salt + password).digest() for i in range(0, len(password)): m.update(mixin[i % 16]) # /* Then something really weird... */ # Also really broken, as far as I can tell. -m i = len(password) while i: if i & 1: m.update('\x00') else: m.update(password[0]) i >>= 1 final = m.digest() # /* and now, just to make sure things don't run too fast */ for i in range(1000): m2 = md5.md5() if i & 1: m2.update(password) else: m2.update(final) if i % 3: m2.update(salt) if i % 7: m2.update(password) if i & 1: m2.update(final) else: m2.update(password) final = m2.digest() # This is the bit that uses to64() in the original code. itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' rearranged = '' for a, b, c in ((0, 6, 12), (1, 7, 13), (2, 8, 14), (3, 9, 15), (4, 10, 5)): v = ord(final[a]) << 16 | ord(final[b]) << 8 | ord(final[c]) for i in range(4): rearranged += itoa64[v & 0x3f]; v >>= 6 v = ord(final[11]) for i in range(2): rearranged += itoa64[v & 0x3f]; v >>= 6 return magic + salt + '$' + rearranged if __name__ == '__main__': def test(clear_password, the_hash): magic, salt = the_hash[1:].split('$')[:2] magic = '$' + magic + '$' return md5crypt(clear_password, salt, magic) == the_hash test_cases = ( (' ', '$1$yiiZbNIH$YiCsHZjcTkYd31wkgW8JF.'), ('pass', '$1$YeNsbWdH$wvOF8JdqsoiLix754LTW90'), ('____fifteen____', '$1$s9lUWACI$Kk1jtIVVdmT01p0z3b/hw1'), ('____sixteen_____', '$1$dL3xbVZI$kkgqhCanLdxODGq14g/tW1'), ('____seventeen____', '$1$NaH5na7J$j7y8Iss0hcRbu3kzoJs5V.'), ('__________thirty-three___________', '$1$HO7Q6vzJ$yGwp2wbL5D7eOVzOmxpsy.'), ('apache', '$apr1$J.w5a/..$IW9y6DR0oO/ADuhlMF5/X1') ) for clearpw, hashpw in test_cases: if test(clearpw, hashpw): print '%s: pass' % clearpw else: print '%s: FAIL' % clearpw PK}68ºk6……acct_mgr/__init__.pyc;ò *ÍìEc@sdS(N((((s5build/bdist.darwin-8.0.1-x86/egg/acct_mgr/__init__.pys?sPK}68[Ïqt~~acct_mgr/api.pyc;ò *ÍìEc@s`dkTdklZlZdefd„ƒYZdefd„ƒYZdefd„ƒYZdS( (s*(sOptionsExtensionOptionsIPasswordStorecBsDtZdZd„Zd„Zd„Zd„Zd„Zd„ZRS(s[An interface for Components that provide a storage method for users and passwords. cCsdS(sí '''Deprecated''': new implementations of this interface are not required to implement this method, since the prefered way to configure the `IPasswordStore` implemenation is by using its class name in the `password_store` option. Returns a string used to identify this implementation in the config. This password storage implementation will be used if the value of the config property "account-manager.password_format" matches. N((sself((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys config_keys cCsdS(s3Returns an iterable of the known usernames N((sself((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys get_users scCsdS(s1Returns whether the user account exists. N((sselfsuser((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pyshas_user$scCsdS(s×Sets the password for the user. This should create the user account if it doesn't already exist. Returns True if a new account was created, False if an existing account was updated. N((sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys set_password(scCsdS(s6Checks if the password is valid for the user. N((sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pyscheck_password/scCsdS(spDeletes the user account. Returns True if the account existed and was deleted, False otherwise. N((sselfsuser((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys delete_user3s( s__name__s __module__s__doc__s config_keys get_usersshas_users set_passwordscheck_passwords delete_user(((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pysIPasswordStores     sIAccountChangeListenercBs)tZdZd„Zd„Zd„ZRS(s6An interface for receiving account change events. cCsdS(sNew user N((sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys user_created<scCsdS(sPassword changed N((sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pysuser_password_changed@scCsdS(sUser deleted N((sselfsuser((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys user_deletedDs(s__name__s __module__s__doc__s user_createdsuser_password_changeds user_deleted(((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pysIAccountChangeListener8s   sAccountManagercBsÀtZdZeeƒeddeƒZeddƒZ e eƒZ e eƒZ d„Z d„Zd„Zd„Zd„Zd „Zd „ZeeƒZd „Zd „Zd „Zd„ZRS(sThe AccountManager component handles all user account management methods provided by the IPasswordStore interface. The methods will be handled by the underlying password storage implementation set in trac.ini with the "account-manager.password_format" setting. saccount-managerspassword_storespassword_formatcCs|iiƒSdS(N(sselfspassword_stores get_users(sself((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys get_users[scCs|ii|ƒSdS(N(sselfspassword_storeshas_usersuser(sselfsuser((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pyshas_user^scCsD|ii||ƒo|id||ƒn|id||ƒdS(Nscreatedspassword_changed(sselfspassword_stores set_passwordsuserspasswords_notify(sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys set_passwordascCs|ii||ƒSdS(N(sselfspassword_storescheck_passwordsuserspassword(sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pyscheck_passwordgscCs+|ii|ƒo|id|ƒndS(Nsdeleted(sselfspassword_stores delete_usersusers_notify(sselfsuser((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys delete_userjscCs8y |i}Wntj o tSnXt||ƒSdS(N(sselfspassword_storesstoresAttributeErrorsFalseshasattrs operation(sselfs operationsstore((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pyssupportsns   cCsƒy |iSWnqtj oe|i}xO|iD]D}t|dtƒ}|tjoq/n|ƒ|jo|Sq/q/W‚nXdS(Ns config_key( sselfs_password_storesAttributeErrors_password_formatsfmtsstoressstoresgetattrsNones config_key(sselfs config_keysfmtsstore((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pyspassword_storevs     cGs5d|}x$|iD]}t||ƒ|ŒqWdS(Nsuser_(sfuncsselfschange_listenersslsgetattrsargs(sselfsfuncsargssl((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys_notify†s  cCs|iid|ƒdS(NsCreated new user: %s(sselfslogsinfosuser(sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys user_createdscCs|iid|ƒdS(NsUpdated password for user: %s(sselfslogsinfosuser(sselfsuserspassword((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pysuser_password_changedscCs|iid|ƒdS(NsDeleted user: %s(sselfslogsinfosuser(sselfsuser((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys user_deleted“s(s__name__s __module__s__doc__s implementssIAccountChangeListenersExtensionOptionsIPasswordStores_password_storesOptions_password_formatsExtensionPointsstoresschange_listenerss get_usersshas_users set_passwordscheck_passwords delete_userssupportsspassword_storespropertys_notifys user_createdsuser_password_changeds user_deleted(((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pysAccountManagerHs&                 N( s trac.cores trac.configsOptionsExtensionOptions InterfacesIPasswordStoresIAccountChangeListeners ComponentsAccountManager(sIAccountChangeListenersOptionsIPasswordStoresExtensionOptionsAccountManager((s0build/bdist.darwin-8.0.1-x86/egg/acct_mgr/api.pys? s)PK}68ÜQ;ÅV V acct_mgr/md5crypt.pyc;ò *ÍìEc@sµdkZdd„Zedjod„Zddfddfd d fd d fd dfddfddffZx>eD]2\ZZeeeƒo deGHqwdeGHqwWndS(Ns$1$cCsªtiƒ} | i|||ƒti|||ƒiƒ} x2t dt |ƒƒD]}| i| |dƒqTWt |ƒ}xC|o;|d@o| idƒn| i|dƒ|dL}q‚W| iƒ} x¶t dƒD]¨}tiƒ} |d@o| i|ƒn| i| ƒ|do| i|ƒn|do| i|ƒn|d@o| i| ƒn| i|ƒ| iƒ} qÞWd}d }xºdd d fddd fd ddfdddfdddffD]v\}} }t| |ƒd>t| | ƒd>Bt| |ƒB}x0t dƒD]"}|||d@7}|d L}q)WqÙWt| dƒ}x0t d ƒD]"}|||d@7}|d L}qpW||d|SdS(Niiisièiis@./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzsii i iiii iii ii?i s$(smd5snewsmsupdatespasswordsmagicssaltsdigestsmixinsrangeslensisfinalsm2sitoa64s rearrangedsasbscsordsv(spasswordssaltsmagicsascsitoa64s rearrangedsisvsmsbsmixinsm2sfinal((s5build/bdist.darwin-8.0.1-x86/egg/acct_mgr/md5crypt.pysmd5cryptsR            C4 $  s__main__cCsE|didƒd \}}d|d}t|||ƒ|jSdS(Nis$i(sthe_hashssplitsmagicssaltsmd5cryptsclear_password(sclear_passwordsthe_hashsmagicssalt((s5build/bdist.darwin-8.0.1-x86/egg/acct_mgr/md5crypt.pystestMss s"$1$yiiZbNIH$YiCsHZjcTkYd31wkgW8JF.spasss"$1$YeNsbWdH$wvOF8JdqsoiLix754LTW90s____fifteen____s"$1$s9lUWACI$Kk1jtIVVdmT01p0z3b/hw1s____sixteen_____s"$1$dL3xbVZI$kkgqhCanLdxODGq14g/tW1s____seventeen____s"$1$NaH5na7J$j7y8Iss0hcRbu3kzoJs5V.s!__________thirty-three___________s"$1$HO7Q6vzJ$yGwp2wbL5D7eOVzOmxpsy.sapaches%$apr1$J.w5a/..$IW9y6DR0oO/ADuhlMF5/X1s%s: passs%s: FAIL(smd5smd5crypts__name__stests test_casessclearpwshashpw(shashpwsclearpwsmd5cryptstests test_casessmd5((s5build/bdist.darwin-8.0.1-x86/egg/acct_mgr/md5crypt.pys?s  ;  E   PK‚}68OuŸ¢&&acct_mgr/admin.pyc;ò *ÍìEc@s›dkZdkTdklZdklZdklZdkl Z dk l Z dk l Z dklZd klZd „Zd efd „ƒYZdS( N(s*(sOption(sPermissionSystem(ssorted(sformat_datetime(sITemplateProvider(sIAdminPageProvider(sAccountManager(s _create_usercCsot|tƒo |i}ngi}ti|ƒD]0\}}t|t ƒo|||fƒq4q4~SdS(N( s isinstancesclss Components __class__sappends_[1]sinspects getmemberssnamesvaluesOption(sclssnamesvalues_[1]((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pys _getoptionss sAccountManagerAdminPagecBsQtZeeƒd„Zd„Zd„Zd„Zd„Zd„Z d„Z RS(NcCst|iƒ|_dS(N(sAccountManagersselfsenvsaccount_manager(sself((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pys__init__#sccs;|iidƒo$ddddfVddddfVndS(Ns TRAC_ADMINsaccountssAccountssconfigs ConfigurationsuserssUsers(sreqspermshas_permission(sselfsreq((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pysget_admin_pages'scCs@|djo|i|ƒSn|djo|i|ƒSndS(Nsconfigsusers(spagesselfs _do_configsreqs _do_users(sselfsreqscatspages path_info((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pysprocess_admin_request,s  c CsÞ|idjo«|iidƒ}|iidd|ƒ|ii }xtt |ƒD]b\} }|iid|| fƒ}|tj o-|ii|i|i|ƒ|iiƒqQqQWny|ii }Wntj o t}nXgi}|iiD]ª} |hd| ii<d| ii<d| |j<dgi}t | ƒD]M\} }|hd | <dd| ii| f<d |i| | ƒ<ƒqL~<ƒqû~}t|d d „ƒ}||id Msssectionssadmin_accountsconfig.cs(sreqsmethodsargssgetsselected_classsselfsconfigssetsaccount_managerspassword_storesselecteds _getoptionssattrsoptionsnewvaluesNonessectionsnamessavesAttributeErrorsappends_[1]sstoressstores __class__s__name__s_[2]s__get__ssectionsssortedshdf( sselfsreqsselectedsoptionssectionss_[1]sselected_classs_[2]snewvaluesstoresattr((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pys _do_config2s$    Ç  cCs¢t|iƒ}|iidƒ} |iidƒ}|iidƒ} | |i d<||i d<| |i d<|i djo÷|i i dƒo^|oFyt||id tƒWqétj o} | i|i d ‚ssaccountssadmin_users.cs('sPermissionSystemsselfsenvspermsaccount_managerssupportsslisting_enabledscreate_enabledsdelete_enabledsreqshdfsmethodsargssgets _create_usersFalses TracErrorsesmessagessels isinstanceslistsaccounts delete_usersaccountss get_userssusernamesget_known_userssnamesemails get_db_cnxsdbscursorsexecutes last_visitsformat_datetimessorteds itervaluessNone(sselfsreqsusernames last_visitsaccountssselspermsemailscreate_enabledsdbslisting_enabledsesdelete_enabledsaccountsnamescursor((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pys _do_usersQsZ         cCsgSdS(s„Return the absolute path of a directory containing additional static resources (such as images, style sheets, etc). N((sself((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pysget_htdocs_dirsˆscCs!dkl}|tdƒgSdS(siReturn the absolute path of the directory containing the provided ClearSilver templates. (sresource_filenames templatesN(s pkg_resourcessresource_filenames__name__(sselfsresource_filename((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pysget_templates_dirsŽs ( s__name__s __module__s implementssIAdminPageProviders__init__sget_admin_pagessprocess_admin_requests _do_configs _do_userssget_htdocs_dirssget_templates_dirs(((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pysAccountManagerAdminPages      7 (sinspects trac.cores trac.configsOptions trac.permsPermissionSystems trac.utilssortedstrac.util.datefmtsformat_datetimestrac.web.chromesITemplateProviderswebadmin.web_uisIAdminPageProviders acct_mgr.apisAccountManagersacct_mgr.web_uis _create_users _getoptionss ComponentsAccountManagerAdminPage( s _getoptionssOptions _create_usersIAdminPageProvidersinspectsformat_datetimesITemplateProvidersPermissionSystemsAccountManagerAdminPagessortedsAccountManager((s2build/bdist.darwin-8.0.1-x86/egg/acct_mgr/admin.pys? s          PK©e6°©Þ:ä8ä8acct_mgr/web_ui.py# -*- coding: utf-8 -*- # # Copyright (C) 2005 Matthew Good # # "THE BEER-WARE LICENSE" (Revision 42): # wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return. Matthew Good # # Author: Matthew Good from __future__ import generators import random import string from trac import perm, util from trac.core import * from trac.config import IntOption from trac.notification import NotificationSystem, NotifyEmail from trac.web import auth from trac.web.api import IAuthenticator from trac.web.main import IRequestHandler from trac.web.chrome import INavigationContributor, ITemplateProvider from trac.util import Markup from api import AccountManager def _create_user(req, env, check_permissions=True): mgr = AccountManager(env) user = req.args.get('user') if not user: raise TracError('Username cannot be empty.') if mgr.has_user(user): raise TracError('Another account with that name already exists.') if check_permissions: # disallow registration of accounts which have existing permissions permission_system = perm.PermissionSystem(env) if permission_system.get_user_permissions(user) != \ permission_system.get_user_permissions('authenticated'): raise TracError('Another account with that name already exists.') password = req.args.get('password') if not password: raise TracError('Password cannot be empty.') if password != req.args.get('password_confirm'): raise TracError('The passwords must match.') mgr.set_password(user, password) db = env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT count(*) FROM session " "WHERE sid=%s AND authenticated=1", (user,)) exists, = cursor.fetchone() if not exists: cursor.execute("INSERT INTO session " "(sid, authenticated, last_visit) " "VALUES (%s, 1, 0)", (user,)) for key in ('name', 'email'): value = req.args.get(key) if not value: continue cursor.execute("UPDATE session_attribute SET value=%s " "WHERE name=%s AND sid=%s AND authenticated=1", (value, key, user)) if not cursor.rowcount: cursor.execute("INSERT INTO session_attribute " "(sid,authenticated,name,value) " "VALUES (%s,1,%s,%s)", (user, key, value)) db.commit() class PasswordResetNotification(NotifyEmail): template_name = 'reset_password_email.cs' _username = None def get_recipients(self, resid): return ([resid],[]) def get_smtp_address(self, addr): """Overrides `get_smtp_address` in order to prevent CCing users other than the user whose password is being reset. """ if addr == self._username: return NotifyEmail.get_smtp_address(self, addr) else: return None def notify(self, username, password): # save the username for use in `get_smtp_address` self._username = username self.hdf['account.username'] = username self.hdf['account.password'] = password self.hdf['login.link'] = self.env.abs_href.login() projname = self.config.get('project', 'name') subject = '[%s] Trac password reset for user: %s' % (projname, username) NotifyEmail.notify(self, username, subject) class AccountModule(Component): """Allows users to change their password, reset their password if they've forgotten it, or delete their account. The settings for the AccountManager module must be set in trac.ini in order to use this. """ implements(INavigationContributor, IRequestHandler, ITemplateProvider) _password_chars = string.ascii_letters + string.digits password_length = IntOption('account-manager', 'generated_password_length', 8, 'Length of the randomly-generated passwords ' 'created when resetting the password for an ' 'account.') def __init__(self): self._write_check(log=True) def _write_check(self, log=False): writable = AccountManager(self.env).supports('set_password') if not writable and log: self.log.warn('AccountModule is disabled because the password ' 'store does not support writing.') return writable #INavigationContributor methods def get_active_navigation_item(self, req): return 'account' def get_navigation_items(self, req): if not self._write_check(): return if req.authname != 'anonymous': yield 'metanav', 'account', Markup('My Account', (req.href.account())) # IRequestHandler methods def match_request(self, req): return (req.path_info in ('/account', '/reset_password') and self._write_check(log=True)) def process_request(self, req): if req.path_info == '/account': self._do_account(req) return 'account.cs', None elif req.path_info == '/reset_password': self._do_reset_password(req) return 'reset_password.cs', None def _do_account(self, req): if req.authname == 'anonymous': req.redirect(self.env.href.wiki()) action = req.args.get('action') delete_enabled = AccountManager(self.env).supports('delete_user') req.hdf['delete_enabled'] = delete_enabled if req.method == 'POST': if action == 'change_password': self._do_change_password(req) elif action == 'delete': self._do_delete(req) def _do_reset_password(self, req): if req.authname != 'anonymous': req.hdf['reset.logged_in'] = True req.hdf['account_href'] = req.href.account() return if req.method == 'POST': username = req.args.get('username') email = req.args.get('email') if not username: req.hdf['reset.error'] = 'Username is required' return if not email: req.hdf['reset.error'] = 'Email is required' return notifier = PasswordResetNotification(self.env) if email != notifier.email_map.get(username): req.hdf['reset.error'] = 'The email and username do not ' \ 'match a known account.' return new_password = self._random_password() notifier.notify(username, new_password) AccountManager(self.env).set_password(username, new_password) req.hdf['reset.sent_to_email'] = email def _random_password(self): return ''.join([random.choice(self._password_chars) for _ in xrange(self.password_length)]) def _do_change_password(self, req): user = req.authname mgr = AccountManager(self.env) old_password = req.args.get('old_password') if not old_password: req.hdf['account.save_error'] = 'Old Password cannot be empty.' return if not mgr.check_password(user, old_password): req.hdf['account.save_error'] = 'Old Password is incorrect.' return password = req.args.get('password') if not password: req.hdf['account.save_error'] = 'Password cannot be empty.' return if password != req.args.get('password_confirm'): req.hdf['account.save_error'] = 'The passwords must match.' return mgr.set_password(user, password) req.hdf['account.message'] = 'Password successfully updated.' def _do_delete(self, req): user = req.authname mgr = AccountManager(self.env) password = req.args.get('password') if not password: req.hdf['account.delete_error'] = 'Password cannot be empty.' return if not mgr.check_password(user, password): req.hdf['account.delete_error'] = 'Password is incorrect.' return mgr.delete_user(user) req.redirect(self.env.href.logout()) # ITemplateProvider def get_htdocs_dirs(self): """Return the absolute path of a directory containing additional static resources (such as images, style sheets, etc). """ return [] def get_templates_dirs(self): """Return the absolute path of the directory containing the provided ClearSilver templates. """ from pkg_resources import resource_filename return [resource_filename(__name__, 'templates')] class RegistrationModule(Component): """Provides users the ability to register a new account. Requires configuration of the AccountManager module in trac.ini. """ implements(INavigationContributor, IRequestHandler, ITemplateProvider) def __init__(self): self._enable_check(log=True) def _enable_check(self, log=False): writable = AccountManager(self.env).supports('set_password') ignore_case = auth.LoginModule(self.env).ignore_case if log: if not writable: self.log.warn('RegistrationModule is disabled because the ' 'password store does not support writing.') if ignore_case: self.log.warn('RegistrationModule is disabled because ' 'ignore_auth_case is enabled in trac.ini. ' 'This setting needs disabled to support ' 'registration.') return writable and not ignore_case #INavigationContributor methods def get_active_navigation_item(self, req): return 'register' def get_navigation_items(self, req): if not self._enable_check(): return if req.authname == 'anonymous': yield 'metanav', 'register', Markup('Register', (self.env.href.register())) # IRequestHandler methods def match_request(self, req): return req.path_info == '/register' and self._enable_check(log=True) def process_request(self, req): if req.authname != 'anonymous': req.redirect(self.env.href.account()) action = req.args.get('action') if req.method == 'POST' and action == 'create': try: _create_user(req, self.env) except TracError, e: req.hdf['registration.error'] = e.message else: req.redirect(self.env.href.login()) req.hdf['reset_password_enabled'] = \ (self.env.is_component_enabled(AccountModule) and NotificationSystem(self.env).smtp_enabled) return 'register.cs', None # ITemplateProvider def get_htdocs_dirs(self): """Return the absolute path of a directory containing additional static resources (such as images, style sheets, etc). """ return [] def get_templates_dirs(self): """Return the absolute path of the directory containing the provided ClearSilver templates. """ from pkg_resources import resource_filename return [resource_filename(__name__, 'templates')] def if_enabled(func): def wrap(self, *args, **kwds): if not self.enabled: return None return func(self, *args, **kwds) return wrap class LoginModule(auth.LoginModule): implements(ITemplateProvider) def authenticate(self, req): if req.method == 'POST' and req.path_info.startswith('/login'): req.environ['REMOTE_USER'] = self._remote_user(req) return auth.LoginModule.authenticate(self, req) authenticate = if_enabled(authenticate) match_request = if_enabled(auth.LoginModule.match_request) def process_request(self, req): if req.path_info.startswith('/login') and req.authname == 'anonymous': req.hdf['referer'] = self._referer(req) if self.env.is_component_enabled(AccountModule) \ and NotificationSystem(self.env).smtp_enabled: req.hdf['trac.href.reset_password'] = req.href.reset_password() if req.method == 'POST': req.hdf['login.error'] = 'Invalid username or password' return 'login.cs', None return auth.LoginModule.process_request(self, req) def _do_login(self, req): if not req.remote_user: req.redirect(self.env.abs_href()) return auth.LoginModule._do_login(self, req) def _remote_user(self, req): user = req.args.get('user') password = req.args.get('password') if not user or not password: return None if AccountManager(self.env).check_password(user, password): return user return None def _redirect_back(self, req): """Redirect the user back to the URL she came from.""" referer = self._referer(req) if referer and not referer.startswith(req.base_url): # don't redirect to external sites referer = None req.redirect(referer or self.env.abs_href()) def _referer(self, req): return req.args.get('referer') or req.get_header('Referer') def enabled(self): # Users should disable the built-in authentication to use this one return not self.env.is_component_enabled(auth.LoginModule) enabled = property(enabled) # ITemplateProvider def get_htdocs_dirs(self): """Return the absolute path of a directory containing additional static resources (such as images, style sheets, etc). """ return [] def get_templates_dirs(self): """Return the absolute path of the directory containing the provided ClearSilver templates. """ from pkg_resources import resource_filename return [resource_filename(__name__, 'templates')] PK}68mháJJacct_mgr/http.pyc;ò *ÍìEc@sZdklZlZlZlZdkTdklZdkl Z de fd„ƒYZ dS((s build_openersHTTPBasicAuthHandlersHTTPDigestAuthHandlersHTTPPasswordMgrWithDefaultRealm(s*(sOption(sIPasswordStores HttpAuthStorecBs*tZeeƒeddƒZd„ZRS(Nsaccount-managersauthentication_urlcCsmtƒ}|it|i||ƒy)tt |ƒt |ƒƒi |iƒWnt j o t SnXtSdS(N(sHTTPPasswordMgrWithDefaultRealmsmgrs add_passwordsNonesselfsauth_urlsuserspasswords build_openersHTTPBasicAuthHandlersHTTPDigestAuthHandlersopensIOErrorsFalsesTrue(sselfsuserspasswordsmgr((s1build/bdist.darwin-8.0.1-x86/egg/acct_mgr/http.pyscheck_passwords   (s__name__s __module__s implementssIPasswordStoresOptionsauth_urlscheck_password(((s1build/bdist.darwin-8.0.1-x86/egg/acct_mgr/http.pys HttpAuthStores N( surllib2s build_openersHTTPBasicAuthHandlersHTTPDigestAuthHandlersHTTPPasswordMgrWithDefaultRealms trac.cores trac.configsOptionsapisIPasswordStores Components HttpAuthStore(s build_openersHTTPPasswordMgrWithDefaultRealmsOptionsIPasswordStoresHTTPDigestAuthHandlers HttpAuthStoresHTTPBasicAuthHandler((s1build/bdist.darwin-8.0.1-x86/egg/acct_mgr/http.pys? s  PK©e6óîA|¢¢acct_mgr/admin.py# -*- coding: utf-8 -*- # # Copyright (C) 2005 Matthew Good # # "THE BEER-WARE LICENSE" (Revision 42): # wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a beer in return. Matthew Good # # Author: Matthew Good import inspect from trac.core import * from trac.config import Option from trac.perm import PermissionSystem from trac.util import sorted from trac.util.datefmt import format_datetime from trac.web.chrome import ITemplateProvider from webadmin.web_ui import IAdminPageProvider from acct_mgr.api import AccountManager from acct_mgr.web_ui import _create_user def _getoptions(cls): if isinstance(cls, Component): cls = cls.__class__ return [(name, value) for name, value in inspect.getmembers(cls) if isinstance(value, Option)] class AccountManagerAdminPage(Component): implements(IAdminPageProvider) def __init__(self): self.account_manager = AccountManager(self.env) # IAdminPageProvider def get_admin_pages(self, req): if req.perm.has_permission('TRAC_ADMIN'): yield ('accounts', 'Accounts', 'config', 'Configuration') yield ('accounts', 'Accounts', 'users', 'Users') def process_admin_request(self, req, cat, page, path_info): if page == 'config': return self._do_config(req) elif page == 'users': return self._do_users(req) def _do_config(self, req): if req.method == 'POST': selected_class = req.args.get('selected') self.config.set('account-manager', 'password_store', selected_class) selected = self.account_manager.password_store for attr, option in _getoptions(selected): newvalue = req.args.get('%s.%s' % (selected_class, attr)) if newvalue is not None: self.config.set(option.section, option.name, newvalue) self.config.save() try: selected = self.account_manager.password_store except AttributeError: selected = None sections = [ {'name': store.__class__.__name__, 'classname': store.__class__.__name__, 'selected': store is selected, 'options': [ {'label': attr, 'name': '%s.%s' % (store.__class__.__name__, attr), 'value': option.__get__(store, store), } for attr, option in _getoptions(store) ], } for store in self.account_manager.stores ] sections = sorted(sections, key=lambda i: i['name']) req.hdf['sections'] = sections return 'admin_accountsconfig.cs', None def _do_users(self, req): perm = PermissionSystem(self.env) listing_enabled = self.account_manager.supports('get_users') create_enabled = self.account_manager.supports('set_password') delete_enabled = self.account_manager.supports('delete_user') req.hdf['listing_enabled'] = listing_enabled req.hdf['create_enabled'] = create_enabled req.hdf['delete_enabled'] = delete_enabled if req.method == 'POST': if req.args.get('add'): if create_enabled: try: _create_user(req, self.env, check_permissions=False) except TracError, e: req.hdf['registration.error'] = e.message else: req.hdf['registration_error'] = 'The password store does ' \ 'not support creating users' elif req.args.get('remove'): if delete_enabled: sel = req.args.get('sel') sel = isinstance(sel, list) and sel or [sel] for account in sel: self.account_manager.delete_user(account) else: req.hdf['deletion_error'] = 'The password store does not ' \ 'support deleting users' if listing_enabled: accounts = {} for username in self.account_manager.get_users(): accounts[username] = {'username': username} for username, name, email in self.env.get_known_users(): account = accounts.get(username) if account: account['name'] = name account['email'] = email db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT sid,last_visit FROM session WHERE authenticated=1") for username, last_visit in cursor: account = accounts.get(username) if account and last_visit: account['last_visit'] = format_datetime(last_visit) req.hdf['accounts'] = sorted(accounts.itervalues(), key=lambda acct: acct['username']) return 'admin_users.cs', None # ITemplateProvider def get_htdocs_dirs(self): """Return the absolute path of a directory containing additional static resources (such as images, style sheets, etc). """ return [] def get_templates_dirs(self): """Return the absolute path of the directory containing the provided ClearSilver templates. """ from pkg_resources import resource_filename return [resource_filename(__name__, 'templates')] PK©e6'£áþþ!acct_mgr/templates/admin_users.cs

Manage User Accounts

Add Account:

Add a new user account.

This password store does not support listing users

  AccountNameEmailLast Login
PK©e6·Ø?‡ggacct_mgr/templates/login.cs PK©e6‹àsåå$acct_mgr/templates/reset_password.cs

Reset Password

Already logged in

You're already logged in. If you need to change your password please use the My Account page.

A new password has been emailed to you at .

If you've forgot your password enter your username and email address below and you'll be emailed a new password.

Error

PK©e6?;  *acct_mgr/templates/reset_password_email.csYour Trac password has been reset. Here is your account information: Login URL: <> Username: Password: -- <> PK©e6ÉŒ³4vvacct_mgr/templates/register.cs

Register an account

Error

Required
Optional

Entering your email address will enable you to reset your password if you ever forget it.

PK©e6N€D4‚‚*acct_mgr/templates/admin_accountsconfig.cs

Accounts: Configuration

PK©e6.F±(__acct_mgr/templates/account.cs

My Account

Manage your user account.

Error

Change Password

Error


Delete Account

Error

PK‰ª28“×2EGG-INFO/zip-safe PKy}68‰M…ÀÀEGG-INFO/SOURCES.txtREADME setup.cfg setup.py TracAccountManager.egg-info/PKG-INFO TracAccountManager.egg-info/SOURCES.txt TracAccountManager.egg-info/dependency_links.txt TracAccountManager.egg-info/entry_points.txt TracAccountManager.egg-info/requires.txt TracAccountManager.egg-info/top_level.txt TracAccountManager.egg-info/zip-safe acct_mgr/__init__.py acct_mgr/admin.py acct_mgr/api.py acct_mgr/htfile.py acct_mgr/http.py acct_mgr/md5crypt.py acct_mgr/web_ui.py PKw}68pÚª®®EGG-INFO/entry_points.txt[trac.plugins] acct_mgr.htfile = acct_mgr.htfile acct_mgr.admin = acct_mgr.admin acct_mgr.api = acct_mgr.api acct_mgr.web_ui = acct_mgr.web_ui acct_mgr.http = acct_mgr.http PKw}68“×2EGG-INFO/dependency_links.txt PKw}68n åOEGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: TracAccountManager Version: 0.1.3dev Summary: User account management plugin for Trac Home-page: http://trac-hacks.org/wiki/AccountManagerPlugin Author: Matthew Good Author-email: trac@matt-good.net License: "THE BEER-WARE LICENSE" (Revision 42): wrote this file. As long as you retain this notice you can do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return. Matthew Good Description: UNKNOWN Platform: UNKNOWN PKv}68¢|‘õ EGG-INFO/requires.txtTracWebAdminPKw}68µgÓ EGG-INFO/top_level.txtacct_mgr PK©e6¤acct_mgr/__init__.pyPK}68.À¸É.*.*¤2acct_mgr/htfile.pycPK‚}68iü)îJQJQ¤‘*acct_mgr/web_ui.pycPK©e6Õ¿—ÈÝݤ |acct_mgr/api.pyPK©e6‘ÈXnn¤acct_mgr/http.pyPK©e6”Q«aÊʤ²“acct_mgr/htfile.pyPK©e6ê♼ ¤¬°acct_mgr/md5crypt.pyPK}68ºk6……¤ë¼acct_mgr/__init__.pycPK}68[Ïqt~~¤£½acct_mgr/api.pycPK}68ÜQ;ÅV V ¤OÝacct_mgr/md5crypt.pycPK‚}68OuŸ¢&&¤Øçacct_mgr/admin.pycPK©e6°©Þ:ä8ä8¤.acct_mgr/web_ui.pyPK}68mháJJ¤B=acct_mgr/http.pycPK©e6óîA|¢¢¤»Cacct_mgr/admin.pyPK©e6'£áþþ!´ŒZacct_mgr/templates/admin_users.csPK©e6·Ø?‡gg´Ébacct_mgr/templates/login.csPK©e6‹àsåå$´ifacct_mgr/templates/reset_password.csPK©e6?;  *´kacct_mgr/templates/reset_password_email.csPK©e6ÉŒ³4vv´älacct_mgr/templates/register.csPK©e6N€D4‚‚*´–racct_mgr/templates/admin_accountsconfig.csPK©e6.F±(__´`vacct_mgr/templates/account.csPK‰ª28“×2¤ú}EGG-INFO/zip-safePKy}68‰M…ÀÀ¤*~EGG-INFO/SOURCES.txtPKw}68pÚª®®¤€EGG-INFO/entry_points.txtPKw}68“×2¤EGG-INFO/dependency_links.txtPKw}68n åO¤=EGG-INFO/PKG-INFOPKv}68¢|‘õ ¤‰ƒEGG-INFO/requires.txtPKw}68µgÓ ¤ÈƒEGG-INFO/top_level.txtPK„