a fWc@sxdZddlmZmZddlZeeZddlZddl Z ddl m Z zddl m ZedeWn ey~eddZYn0dd lmZmZdd lmZdd lmZdd lmZmZmZmZdd lmZgdZdZ GdddZ!dddddZ"ddZ#dZ$dZ%dZ&e'dgZ(ddZ)Gdd d e*Z+Gd!d"d"e+Z,d#Z-Gd$d%d%e*Z.Gd&d'd'e*Z/e*Z0Gd(d)d)e*Z1dS)*z?passlib.ext.django.utils - helper functions used by this plugin)update_wrapperwrapsN)warn)VERSIONzfound django %r installationzdjango installation not found)excregistry) CryptContext)PasslibRuntimeWarning)get_method_function iteritems OrderedDictunicode)memoized_property)DJANGO_VERSIONMIN_DJANGO_VERSIONget_preset_configquirks)c@s$eZdZedkZedkZedkZdS)rrN)__name__ __module__ __qualname__rZ none_causes_check_password_errorZempty_is_usable_passwordZinvalid_is_usable_passwordrrr.wrapper)r)r+r,rr*r _wrap_methodsr-cseZdZdZdZdZdZdZdfdd ZddZ ddZ d d Z dd d Z e ddZedkrjejddddZddZdddZdddZZS)DjangoTranslatoraO Object which helps translate passlib hasher objects / names to and from django hasher objects / names. These methods are wrapped in a class so that results can be cached, but with the ability to have independant caches, since django hasher names may / may not correspond to the same instance (or even class). Nc s<tt|jfi||dur$||_t|_t|_dSr&) superr.__init__contextweakrefWeakKeyDictionary_django_hasher_cacheWeakValueDictionary_passlib_hasher_cache)selfr1r) __class__rrr0s  zDjangoTranslator.__init__cCs|j|jd|_dSr&)r4clearr6_django_unsalted_sha1r7rrr reset_hasherss  zDjangoTranslator.reset_hasherscCs&|j}|durt|S||SdS)zM resolve passlib hasher by name, using context if available. N)r1rget_crypt_handlerhandler)r7 passlib_namer1rrr_get_passlib_hashers z$DjangoTranslator._get_passlib_hashercCs ||jS)zF Convert passlib hasher / name to Django hasher name. )passlib_to_django algorithm)r7r@rrrpasslib_to_django_namesz'DjangoTranslator.passlib_to_django_nameTcCs|t|ds||}|rV|j}z ||WSty:Yn0|j|dd}||<|St|dd}|rp||St|SdS)z Convert passlib hasher / name to Django hasher. :param passlib_hasher: passlib hasher / name :returns: django hasher instance r#Fcached django_nameN)hasattrrAr4r!rBr"_create_django_hasher_PasslibHasherWrapper)r7passlib_hasherrFcacheresultrGrrrrBs       z"DjangoTranslator.passlib_to_djangoZMD5PasswordHasher)Zmd5rZBCryptPasswordHasher)Zbcryptc Cstjd}|dus|jjsjddlm}z ||WStyf}zt| dsRWYd}~qd}~00n.|jj dj }|D]}|j |kr|Sq|j|}|rd|vrd|}dd lm}||Std |dS) zf helper to create new django hasher by name. wraps underlying django methods. zpasslib.ext.django.modelsNr) get_hasherz"Unknown password hashing algorithmz'django.contrib.auth.hashers:get_hashers.zdjango.contrib.auth.hashers.) import_stringzunknown hasher: %r)sysmodulesgetZadapterpatcheddjango.contrib.auth.hashersrNrstr startswith_managergetorig __wrapped__rC_builtin_django_hashersZdjango.utils.module_loadingrP) r7rGmodulerNerr get_hashershasherpathrPrrrrIs&         z&DjangoTranslator._create_django_hashercCs ||jS)zF Convert Django hasher / name to Passlib hasher name. )django_to_passlibr#)r7rGrrrdjango_to_passlib_name+sz'DjangoTranslator.django_to_passlib_namec Cst|dr t|tr|jS|j}|rb|j}z ||WStyFYn0|j|dd}||<|S|t r|t t d}| |S|dkr|j }|durt d|S|dkrd}|j }|durd d tD}n |jd d }|D]}t|d d|kr|Sqtd|fdS)a Convert Django hasher / name to Passlib hasher / name. If present, CryptContext will be checked instead of main registry. :param django_name: Django hasher class or algorithm name. "default" allowed if context provided. :raises ValueError: if can't resolve hasher. :returns: passlib hasher or name rCFrENdefaultz)can't determine default scheme w/ context unsalted_sha1Zsha1css*|]"}|ts|tvrt|VqdSr&)rWDJANGO_COMPAT_PREFIX_other_django_hashesrr>).0r@rrr ns z5DjangoTranslator.django_to_passlib..TresolverGz/can't translate django name to passlib name: %r)rH isinstancerJpasslib_handlerrCr6r!rarWPASSLIB_WRAPPER_PREFIXlenrAr1 TypeErrorr?rZlist_crypt_handlersschemesr"r) r7rGrFrLrMr@r1Z candidatesr?rrrra1sF         z"DjangoTranslator.django_to_passlibcCslt|dr|S|j||d}|dkr^|jdkr^|s<||S|j}|durZ||}|_|S|j||dS)zH Take in a django algorithm name, return django hasher. rCrErddjango_salted_sha1N)rHrar#rIr;rB)r7rGrFrKrMrrrresolve_django_hashers   z&DjangoTranslator.resolve_django_hasher)N)T)T)T)rrr__doc__r1r4r;r6r0r=rArDrBdictr[rupdaterIrbrarr __classcell__rrr8rr.s* & Ur.c sBeZdZdZdZdZdZdZdZdZ d1fdd Z fddZ d d Z d2d d Z ddZd3ddZd4ddZddZddZddZdZdZedZdZeddedd fed!d"edd fed#d$fed#d%fed#d&fed#d'fed#d(fed#d$fed#d%fed#d'fed#d(fg Zd)d*Zd+d,Zd-d.Zd/d0ZZS)5DjangoContextAdapteraC Object which tries to adapt a Passlib CryptContext object, using a Django-hasher compatible API. When installed in django, :mod:`!passlib.ext.django` will create an instance of this class, and then monkeypatch the appropriate methods into :mod:`!django.contrib.auth` and other appropriate places. NTFc sttd|_|durt}tt|jfd|i||rNt|sHJ||_ zddl m }Wnt y|ddl m }Yn0||j|_ddlm}|jdrt|}||_ddlm}||_ttd}t|d |_dS) Nz.DjangoContextAdapterr1r) lru_cache) make_passwordzpasslib.)is_password_usablez.DjangoContextAdapter._manager)log)logging getLoggerrr{r r/rwr0callableget_user_category functoolsrx ImportErrorZdjango.utils.lru_cacher^rUryrrW _PatchManagerpeek_unpatched_func_orig_make_passwordrzrX)r7r1rr)rxryrzZmlogr8rrr0s(      zDjangoContextAdapter.__init__cs(ddlm}|ddtt|dS)zH Wrapper to manually reset django's hasher lookup cache r)r=ZPASSWORD_HASHERS)ZsettingN)rUr=r/rw)r7r=r8rrr=s  z"DjangoContextAdapter.reset_hasherscs"|jfdd|jjddDS)zq Passlib replacement for get_hashers() -- Return list of available django hasher classes csg|] }|qSrr)rgr_rBrr sz4DjangoContextAdapter.get_hashers..Tri)rBr1rpr<rrrr^s  z DjangoContextAdapter.get_hashersrccCs ||S)z^ Passlib replacement for get_hasher() -- Return django hasher by name )rr)r7rCrrrrN szDjangoContextAdapter.get_hashercCs:|jj|ddd}|jdkr0|dr0|dS||S)zl Passlib replacement for identify_hasher() -- Identify django hasher based on hash. T)rjrequiredrqzsha1$$rd)r1identifyr#rWrNrB)r7encodedr?rrridentify_hashers z$DjangoContextAdapter.identify_hashercCsZ|dur|dS||}d|jvr(n(|dr@|jdd}n|rP|j|d}||S)z9 Passlib replacement for make_password() NsaltZ unsalted_)r)rra setting_kwdsrWusinghash)r7passwordrr_rKrrrry#s     z"DjangoContextAdapter.make_passwordcCs|dus||sdS|j}z|||}WntjyBYdS0|rL|sP|S|dkrl|j||ds|Sn&||}||r|j||ds|S|||S)z: Passlib replacement for check_password() NFrc)Zsecret)rzr1verifyrUnknownHashError needs_updaterar)r7rrsetterZ preferredr1Zcorrectr_rrrcheck_password:s&   z#DjangoContextAdapter.check_passwordcCsz|dur dS|j}||s dS||}z|jj|||d\}}WntjyZYdS0|rv|durv||_||S)z? Passlib replacement for User.check_password() NFcategory)rrzrr1Zverify_and_updaterrZsave)r7userrrcatokZnew_hashrrruser_check_passwordls   z(DjangoContextAdapter.user_check_passwordcCs2|dur|n||}|jj||d|_dS)z= Passlib replacement for User.set_password() Nr)Zset_unusable_passwordrr1rr)r7rrrrrruser_set_passwords  z&DjangoContextAdapter.user_set_passwordcCs|jr dS|jrdSdSdS)z Helper for hashing passwords per-user -- figure out the CryptContext category for specified Django user object. .. note:: This may be overridden via PASSLIB_GET_CATEGORY django setting Z superuserZstaffN)Z is_superuserZis_staff)r7rrrrrs z&DjangoContextAdapter.get_user_categoryzdjango.contrib.auth.hasherszdjango.contrib.auth.modelsz:Userzdjango.contrib.auth.formsz.check_passwordrr*z .set_passwordr:rryr^rNrcCs|j}|jr|ddSttkr0tdtf|d|j}|jD]^}t |dkr`|if7}|\}}}| dr|||7}t ||}| drt |}|||qF|d|_|d dS) zI Install monkeypatch to replace django hasher framework. z3monkeypatching already applied, refusing to reapplyFz(passlib.ext.django requires django >= %sz#preparing to monkeypatch django ...r)r,r+Tz"... finished monkeypatching django)r{rTwarningrr RuntimeErrordebugrXpatch_locationsrnendswithr"rSr-patchr=)r7r{managerrecordtargetsourceZoptsvaluerrr install_patchs0          z"DjangoContextAdapter.install_patchcCs|j}|j}|jrP|d|jdd|jid|_||ddS|r| d||ji||ddS|ddS)a Remove monkeypatch from django hasher framework. As precaution in case there are lingering refs to context, context object will be wiped. .. warning:: This may cause problems if any other Django modules have imported their own copies of the patched functions, though the patched code has been designed to throw an error as soon as possible in this case. z!removing django monkeypatching...T)unpatch_conflictsFz*...finished removing django monkeypatchingz-reverting partial monkeypatching of django...zdjango not monkeypatched) r{rXrTr unpatch_allr1loadr=isactiver)r7r{rrrr remove_patchs&         z!DjangoContextAdapter.remove_patchcCsZ||jr4z |WqL|YqL0n|jrDtd|tddS)zD Load configuration from django, and install patch. z.didn't expect monkeypatching would be applied!zpasslib.ext.django loadedN)_load_settingsenabledrrrTr{errorrr<rrr load_models   zDjangoContextAdapter.load_modelcCsddlm}t}t|d|}||ur2t|d|}||ur>d}|durVtdtd}nt|ttt fstt |d dt|d d}|rt |st |d d |dkrd |_ dS|jd dt|trd|vrt|}|r||_n|jdd|j||dS)z- Update settings from django r)settingsZPASSLIB_CONFIGZPASSLIB_CONTEXTrNz}setting PASSLIB_CONFIG=None is deprecated, and support will be removed in Passlib 1.8, use PASSLIB_CONFIG='disabled' instead.Zdisabledz str or dictZPASSLIB_GET_CATEGORYr~Fr get_category)Z django.confrobjectr"rDeprecationWarningrkrbytesrtrZExpectedTypeErrorr~r__dict__poprVrrr1rr=)r7r_UNSETZconfigrrrrr#s8      z#DjangoContextAdapter._load_settings)NN)rc)Nrc)Nrc)rrrrsr1rrzrXrrTr0r=r^rNrryrrrrZ HASHERS_PATHZ MODELS_PATHZUSER_CLASS_PATHZ FORMS_PATHrtrrrrrrvrrr8rrwsJ $    2           *'rwz--!!!generate-new-salt!!!--c@s0eZdZdZddZddZddZdd Zd S) ProxyPropertyz%helper that proxies another attributecCs ||_dSr&)r$)r7r$rrrr0gszProxyProperty.__init__cCs|dur |}t||jSr&)r"r$)r7objclsrrr__get__jszProxyProperty.__get__cCst||j|dSr&)setattrr$)r7rrrrr__set__oszProxyProperty.__set__cCst||jdSr&)delattrr$)r7rrrr __delete__rszProxyProperty.__delete__N)rrrrsr0rrrrrrrrds rc@s~eZdZdZdZddZddZeddZed d Zed d Z ed dZ ddZ ddZ dddZ ddZddZdS)rJz adapter which which wraps a :cls:`passlib.ifc.PasswordHash` class, and provides an interface compatible with the Django hasher API. :param passlib_handler: passlib hash handler (e.g. :cls:`passlib.hash.sha256_crypt`. NcCsRt|ddrtd|jf|jr0td|j||_|jrN|j|_td|_ dS)NrGzHhandlers that reflect an official django hasher shouldn't be wrapped: %rz%can't wrap disabled-hash handlers: %rrounds) r"rr#Z is_disabledrl _has_roundsZdefault_roundsrr iterations)r7rlrrrr0s z_PasslibHasherWrapper.__init__cCs d|jS)Nz!)rlr<rrr__repr__sz_PasslibHasherWrapper.__repr__cCsd|jjS)NzPasslib_%s_PasswordHasher)rlr#titler<rrrrsz_PasslibHasherWrapper.__name__cCs d|jjvS)Nr)rlrr<rrrrsz!_PasslibHasherWrapper._has_roundscCs(tdd}|jr$d|jjvr$d|d<|S)zy internal helper for safe_summary() -- used to translate passlib hash options -> django keywords r)ZchecksumZpbkdf2rr)rtrrlr#)r7outrrr_translate_kwdss z%_PasslibHasherWrapper._translate_kwdscCs t|jjSr&)rmrlr#r<rrrrCsz_PasslibHasherWrapper.algorithmcCstSr&)_GEN_SALT_SIGNALr<rrrrsz_PasslibHasherWrapper.saltcCs|j||Sr&)rlr)r7rrrrrrsz_PasslibHasherWrapper.verifycCsi}|dur|tkr||d<|jrR|dur4||d<qp|durF||d<qp|j|d<n|dusb|durptd|j|j}|r|jfi|}||S)Nrrz0%s.hash(): 'rounds' and 'iterations' are ignored)rrrrrrlrr)r7rrrrr)r?rrrencodes   z_PasslibHasherWrapper.encodec Csddlm}ddlm}|j}|d|jfg}t|drx|j||d}t|D](\}}|j ||}| |||fqNt |S)Nr) mask_hash) ugettext_nooprC parsehash)Zsanitize) rUrZdjango.utils.translationrrlr#rHrr rrSappendr ) r7rr_r?itemsr)keyrrrr safe_summarys    z"_PasslibHasherWrapper.safe_summarycCs,|jr(|jj|j|jd}||r(dSdS)N)Z min_roundsZ max_roundsTF)rrlrrr)r7rsubclsrrr must_updates  z!_PasslibHasherWrapper.must_update)NNN)rrrrsrlr0rrrrrCrrrrrrrrrrJvs"       rJc@seZdZdZd!ddZddZeZZddZe d d Z e fd d Z d"d dZ d#ddZd$ddZddZd%ddZeddZd&ddZd'ddZdd ZdS)(rz4helper to manage monkeypatches and run sanity checksNcCs|pttd|_i|_dS)Nz._PatchManager)r|r}rr{_state)r7r{rrrr0bsz_PatchManager.__init__cCs t|jSr&)boolrr<rrrrhsz_PatchManager.isactivecCsJ|d\}}t||gdd}d|vrB|dd\}}t||}q||fS)z8retrieve obj and final attribute name from resource pathrr)fromlistlevelrOr)split __import__r")r7r`r#r$rheadrrr _import_pathos  z_PatchManager._import_pathcCst|t|kS)zAcheck if two values are the same (stripping method wrappers, etc))r )leftrightrrr_is_same_valuexsz_PatchManager._is_same_valuecCs||\}}t|||Sr&)rr")r7rrcrr$rrr _get_pathsz_PatchManager._get_pathcCs |||S)zreturn current value for path)r)r7r`rcrrrrSsz_PatchManager.getcCs@z|j|\}}Wnty.||}Yn0|tur<|S|S)z*return original (unpatched) value for path)rr!rr)r7r`rcrrrrrrYs  z_PatchManager.getorigFcCsT|j}t|jD]>\}\}}||||r.qd|}|rDt|qt|tqdS)z:run sanity check on all keys, issue warning if out of syncz(another library has patched resource: %rN)rr rrrrr )r7strictZsamer`origexpectedmsgrrr check_alls z_PatchManager.check_allcCs<||\}}|tur,t||r8t||n t|||dSr&)rrrHrr)r7r`rrr$rrr _set_paths   z_PatchManager._set_pathcs|tks J||}z|j|\}}Wn$tyL|jd||}Yn*0|jd||||svtd|t|rt |sJ||fdd}t |||}t |r|t |_ | ||||f|j|<dS)zBmonkeypatch object+attr at to have , stores originalzpatching resource: %rzmodifying resource: %rz4overridding resource another library has patched: %rcsg|Ri|Sr&rr'wrappedZ wrapped_byrrr,sz$_PatchManager.patch..wrapperN)rrrr!r{rrrr r~rr _patched_original_valuer)r7r`rwrapcurrentrrr,rrrrs2         z_PatchManager.patchcCs|jSr&)r)rrrrrrsz!_PatchManager.peek_unpatched_funcTcs4fdd}tr0}d||dS|S)zBfunction decorator which patches function of same name in cs:r6dvrdnd}|p"|j}j||d|S)NrrO)r)rr)funcsepr`enabler#parentr7rrrbuilders z*_PatchManager.monkeypatch..builderN)r~)r7rr#rrrrrrr monkeypatchsz_PatchManager.monkeypatchcCsz|j|\}}Wnty&YdS0||}|jd||||sz|r`td|tntd|t|j|=dS||||j|=dS)Nzunpatching resource: %rz2reverting resource another library has patched: %rz6not reverting resource another library has patched: %r) rr!rr{rrrr r)r7r`rrrrrrrunpatchs,    z_PatchManager.unpatchcKs&t|jD]}|j|fi|q dSr&)listrr)r7r)rrrrrsz_PatchManager.unpatch_all)N)N)N)F)F)NTF)T)rrrrsr0r__bool__Z __nonzero__r staticmethodrrrrSrYrrr classmethodrrrrrrrrrXs$           r)2rsrrrr|r}rr{rQr2warningsrZdjangorrrrr%rrZpasslib.contextr Z passlib.excr Zpasslib.utils.compatr r r rZpasslib.utils.decorr__all__rrr rrrmresetrfr-rr.rwrrrJrrrrrrsV        '  :a