Xc@sdZddlmZddlmZddlZddlmZmZddl Z ddl Z e j e Z ddlZddlZddlZddlZddlZddlZddlZddlmZmZddlmZmZddlZddlmZdd lmZdd lmZddl j!Z!dd l"m#Z$m%Z%m&Z&m'Z'm(Z(dd l)m*Z*m+Z+m,Z,m-Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4dd lm5Z5m6Z6m7Z7m8Z8m9Z9ddl:m;Z;ddl<j=j>Z?dddddgZ@yddlAZBWneCk r0eDZEnXeFZEdZGdZHeHe3ZIdddgZJeJjKejLjMddjNjOZPeQeQdZRdZSeQdZTdZUeQeDdZVdZWd ZXd!ZYejZd"Z[d#Z\d$Z]d%Z^d&Z_d'Z`d(ZaeQd)d*d+Zbd,d-d.Zcde$fd/YZ#d0dgZdde#fd1YZed2eefd3YZfd4eefd5YZgd6eefd7YZhd8ejifd9YZjdS(:shelpers for passlib unittestsi(twith_statement(t unhexlifyN(twrapstpartial(tPasslibHashWarningtPasslibConfigWarning(tPY3tJYTHON(twarn(texc(tMissingBackendError(tTestCasetskiptskipIft skipUnlesstSkipTest( thas_rounds_infot has_salt_infotrounds_cost_valuestrngt getrandstrt is_ascii_safet to_native_strt repeat_stringtticktbatch(t iteritemstirangetutunicodetPY2(t classpropertyt TEST_MODEtset_filetget_fileR t HandlerCasecCsRtjj|}x9tjj||krMtjdtj|dqWdS(sensure file's mtime has changedg?N(tostpathtgetmtimettimetsleeptutimetNone(R%tlast((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytensure_mtime_changed;s cs/fdtfdtdDS(Ncs1}}x||kr(}qW||S(N((tstarttcur(ttimer(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytsampleEs  c3s|]}VqdS(N((t.0t_(R0(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys Jsi(tmintrange(R/((R0R/s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_get_timer_resolutionDstquicktdefaulttfulltPASSLIB_TEST_MODEcCsB|rttj|krtS|r>ttj|kr>tStS(scheck if test for specified mode should be enabled. ``"quick"`` run the bare minimum tests to ensure functionality. variable-cost hashes are tested at their lowest setting. hash algorithms are only tested against the backend that will be used on the current host. no fuzz testing is done. ``"default"`` same as ``"quick"``, except: hash algorithms are tested at default levels, and a brief round of fuzz testing is done for each hash. ``"full"`` extra regression and internal tests are enabled, hash algorithms are tested against all available backends, unavailable ones are mocked whre possible, additional time is devoted to fuzz testing. (t _test_modet _TEST_MODEStindextFalsetTrue(R3tmax((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR Ts cCs2t|drtSd|jkp1t|tjS(s'check if handler supports 'relaxed' kwdt orig_prefixtrelaxed(thasattrR=t setting_kwdst issubclasstuhtGenericHandler(thandler((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pythas_relaxed_settingpscCs"t|}|d|dtjS(s'get effective rounds value from handlertroundst use_defaults(tunwrap_handlerR>RI(RGRI((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_effective_rounds|s cCs[y|j}Wntk r$tSXz!|jd|j|kSWd|j|XdS(s*check if backend is the default for sourceR7N(t get_backendR R=t set_backend(RGtbackendtorig((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytis_default_backends  ccs|dkr|j}n|j}|r=|j|dnd}x5||D])}||krN|j|rN|VqNqNWdS(s iterate over alternate backends available to handler. .. warning:: not thread-safe due to has_backend() call iiN(R*RMtbackendsR<t has_backend(RGtcurrenttfallbackRRtidxRO((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytiter_alt_backendss  cOsxt||D]}|SWdS(N(RWR*(targstkwdsRO((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_alt_backendscCs#xt|dr|j}qW|S(s5return original handler, removing any wrapper objectstwrapped(RBR[(RG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRKs cCs||krtSt|tjrLx#|rG||kr;tS|j}q%WtSt|trzt|tjrzt||St d|fdS(sG test if was derived from via . s%don't know how to inspect handler: %rN( R>t isinstanceREt PrefixWrappert _derived_fromR=ttypeRDtMinimalHandlertNotImplementedError(RGtbase((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pythandler_derived_froms    ! c#st|tr[t|tjr[|jfd}||_z dVWd|_Xn9t|tjrt|j dVWdQXn dVdSdS(s internal helper for do_config_encrypt() -- context manager which temporarily replaces handler's _calc_checksum() with one that uses min_rounds; useful when trying to generate config with high rounds value, but don't care if output is correct. cs:|j}z |j|_|||SWd||_XdS(N(RIt min_rounds(tselfRXRYRI(R[(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytwrappers   N( R\R_RDREt HasRoundst_calc_checksumR]tpatch_calc_min_roundsR[(RGRf((R[s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRis!    cCsJt|tr!|jd}nt|d}|j|WdQXdS(sset file to specified bytessutf-8twbN(R\Rtencodetopentwrite(R%tcontenttfh((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR!scCs&t|d}|jSWdQXdS(sread file as bytestrbN(Rltread(R%Ro((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR"scCsYt|ts|Str&|jdSy|jdSWntk rT|jdSXdS(s*convert native string to non-native stringsutf-8slatin-1N(R\tstrRRktdecodetUnicodeDecodeError(tsource((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttonns  cCsttjdd|S(sT helper for represent byte strings in hex. usage: ``hb("deadbeef23")`` s\st(Rtretsub(Ru((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pythbscCs$||kr|S||kr |S|S(N((tvaluetlowertupper((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytlimits   cCs't}xt||kr"q WdS(sAbecause time.sleep() doesn't even have 10ms accuracy on some OSesN(R(tdelayR-((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt quicksleeps ii c Csddlm}ddlm}||d|p2d}d}t|}xXtrt|j||} t|kr| |t||dfS|d9}qNWdS( s timeit() wrapper which tries to get as accurate a measurement as possible w/in maxtime seconds. :returns: ``(avg_seconds_per_call, log10_number_of_repetitions)`` i(tTimer(tlogtsetupRwii N( ttimeitRtmathRRR>R3trepeattint( tfuncRtmaxtimetbestofRRR/tnumbertendtdelta((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt time_call s  iIj?$csfd}|S(s< decorator run test method w/ multiple fixed seeds. cs%tfd}|S(NcsJtj}x4tD]&}|jd|d<||qWdS(Ni tseed(trandomtRandomRt getrandbits(RXRYRR2(tcountRt master_seed(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRf s(R(RRf(RR(Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytbuilders!((RRR((RRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrun_with_fixed_seedsscBsNeZdZdZdZedZedZe Z e Z dZ dZ e ZdZddZdZeZZdddddddd Zd ejfd YZdddd Zdd ZdZdZdZdZdZej Z!dZ"dZ#dddZ$dZ%dZ&e e'dZ(RS(sRpasslib-specific test case class this class adds a number of features to the standard TestCase... * common prefix for all test descriptions * resets warnings filter & registry for every test * tweaks to message formatting * __msg__ kwd added to assertRaises() * suite of methods for matching against warnings cCsGtt|j}|j}|rCd||p9t|f}n|S(s;wrap shortDescription() method to prepend descriptionPrefixs%s: %s(tsuperR tshortDescriptiontdescriptionPrefixRr(Retdesctprefix((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRBs  cCs,|j}|jdp+t|d|tS(NR2s_%s__unittest_skip(t__name__t startswithtgetattrR=(tclstname((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt__unittest_skip__Ns cCs|j S(N(R(R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt__test__UscCs!tt|j|jdS(N(RR tsetUpt setUpWarnings(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRdscCsS|jrOt}|j|j|jtjddtjddndS(s6helper to init warning filters before subclass setUp()tignores<the method .*\.(encrypt|genconfig|genhash)\(\) is deprecateds&the 'vary_rounds' option is deprecatedN(tresetWarningStatetreset_warningst __enter__t addCleanupt__exit__twarningstfilterwarnings(Retctx((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRhs    cCsF|jr8|r8|jjdr8d|j|fS|pA|SdS(Nt:s%s %s(t longMessagetrstriptendswith(Retmsgtstd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_formatMessage{s$c Os|jdd}|dkr=tt|j|d||Sy|||}Wn|k rf}|SXd||f}|j|j||dS(Nt__msg__s-function returned %r, expected it to raise %r(tpopR*RR t assertRaisestfailureExceptionR( Ret _exc_typet _callableRXRYRtresultterrR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs   cOstddS(Ns%this alias is deprecated by unittest2(tAssertionError(Retatk((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt assertEqualssc CsOt|dr!|} |j}nd} |rI|jt|||n|rk|jt|||n|r|j|||n|s|r| stdn| j} | j ds| j dr| d } n|r|j| ||n|r|j| ||qn|rK| s2tdn|j| j ||ndS(scheck if warning matches specified parameters. 'warning' is the instance of Warning to match against; can also be instance of WarningMessage (as returned by catch_warnings). tcategorys7matching on filename requires a WarningMessage instances.pycs.pyois5matching on lineno requires a WarningMessage instanceN( RBtmessageR*t assertEqualRrt assertRegextassertIsInstancet TypeErrortfilenameRtlineno( Retwarningt message_reRRt filename_reRRRtwmsgtreal((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt assertWarnings0     t_AssertWarningListcBs)eZdZdZdZdZRS(s'context manager for assertWarningList()cKs>||_||_ttj||_|jjdtdS(Ntrecord(tcaseRYRR Rt_AssertWarningList__supert__init__R>(ReRRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs  cCs|jj|_dS(N(RRR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRscGs@|jj||ddkr<|jj|j|jndS(Ni(RRR*RtassertWarningListRRY(Retexc_info((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs(Rt __module__t__doc__RRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs  cCs|dkr7|dk st|j|d|d|S|dk sItt|ttfsj|g}nxt|D]\}}t|trtd|}nNt|t rt |t rtd|}nt|tst dny||}Wnt k rPnX|j|d||qwWt|t|krKdSdt|t||j||f}|j|j||dS(sBcheck that warning list (e.g. from catch_warnings) matches patternRRRRs#entry must be str, warning, or dictNs0expected %d warnings, found %d: wlist=%s desc=%r(R*RRR\tlistttuplet enumerateRrtdictR_RDtWarningRt IndexErrorRtlent_formatWarningListRR(RetwlistRRRVtentrytdataR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs.   (cOs3|dkrg}n|j|||||2dS(sD[deprecated] assertWarningList() variant that clears list afterwardsN(R*R(ReRRRXRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytconsumeWarningLists  cCsd}t|drWd|j|jf}|jrK|d|jf7}n|j}nt|}d|j|jt||fS(NRwRs filename=%r lineno=%rs line=%rs<%s.%s message=%r%s>( RBRRtlineRR_RRRr(ReRttailR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_formatWarnings   cs!ddjfd|DS(Ns[%s]s, c3s|]}j|VqdS(N(R(R1R(Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys s(tjoin(ReR((Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR scCs@ddlm}|s<ddlm}|jd|ndS(s,helper to skip test if stringprep is missingi(t stringprep(t_stringprep_missing_reasons%not available - stringprep module is N(t passlib.utilsRRtskipTest(ReRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_stringpreps  cCs&t|s"|jd|ndS(s8skip test for all PASSLIB_TEST_MODE values below srequires >= %r test modeN(R R(Retlevel((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_TEST_MODEs cCstr|jdSdS(s'skip test if writeable FS not availables.GAE doesn't offer read/write filesystem accessN(tGAER(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_writeable_filesystemsR7c Csc|j}|r#||kr#||S|j1|j}|rP||krP||S|sfi}|_n|prtj}|dkrttjjdptjjdpt j d}t_t j d|nt |}djt||j|j|j|g}tj|jdj}t|d d}tj|}||<|SWdQXdS( sU Return a :class:`random.Random` object for current test method to use. Within an instance, multiple calls with the same name will return the same object. When first created, each RNG will be seeded with value derived from a global seed, the test class module & name, the current test method name, and the **name** parameter. The global seed taken from the $RANDOM_TEST_SEED env var, the $PYTHONHASHSEED env var, or a randomly generated the first time this method is called. In all cases, the value is logged for reproducibility. :param name: name to uniquely identify separate RNGs w/in a test (e.g. for threaded tests). :param seed: override global seed when initialzing rng. :rtype: random.Random tRANDOM_TEST_SEEDtPYTHONHASHSEEDi susing RANDOM_TEST_SEED=%ds sutf-8iN(t _random_cachet_random_global_lockR t_random_global_seedR*RR$tenvirontgettsys_rngRRtinfoR_RRrRRt_testMethodNamethashlibtsha256Rkt hexdigestRR( ReRRtcachet global_seedRRutdigestR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt getRandom2s,     cs|jtj||\}}tj||jdkrpg|_fd}|j|nj||S(s1create temp file that's cleaned up at end of testcs;x0D](}tjj|rtj|qqW2dS(N(R$R%texiststremove(R%(tqueue(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcleaner|s N( RttempfiletmkstempR$tcloset _mktemp_queueR*Rtappend(ReRXRYtfdR%R((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytmktempts      csyt}Wn<tk rQ|r/nfd}|j|nX|jt||rt||}t||nt|dS(s=monkeypatch object value, restoring original value on cleanupcs)ytWntk r$nXdS(N(tdelattrtAttributeError((tattrtobj(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcleanups N(RRRtsetattrRR(ReRRR{trequire_existingtwrapRPR((RRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt patchAttrs N()RRRR*RRRRRR>t_TestCase__unittest_skipRRRRRRRtassertNotEqualstassertRegexMatchesRRtcatch_warningsRRRRRRRRt threadingtLockRRRRR R R=R(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR -sD         +     @ tanycBseZdZdYZdYZgZgZgZgZ gZ dZd[d\gZ e de dd gZ eZeZeZeZed ZeZed Zed Zd ZdYedZdZdZdZedYdYdZ dYdZ!dZ"dZ#dZ$dYdYdZ%dZ&edZ'edZ(dZ)dZ*dZ+dZ,edZ-d Z.d!Z/d"Z0d#Z1d$Z2d%Z3ed&Z4d'Z5d(Z6d)Z7eZ8d*Z9d+Z:ed,Z;d-Z<d.Z=d/Z>d0Z?d1Z@d2ZAd3ZBd4ZCd5ZDd6ZEd7ZFd8ZGd9ZHd:ZId;ZJd<ZKd=ZLd>ZMd?ZNd@ZOdAZPdBZQdCZRdDZSdEZTdFZUdGZVdHZWdIZXdJZYdKZZdLZ[dMZ\dNZ]edOZ^dPZ_edQZ`edRZad]ZbedTZcdUZddVeefdWYZfdXZgRS(^sbase class for testing password hash handlers (esp passlib.utils.handlers subclasses) In order to use this to test a handler, create a subclass will all the appropriate attributes filled as listed in the example below, and run the subclass via unittest. .. todo:: Document all of the options HandlerCase offers. .. note:: This is subclass of :class:`unittest.TestCase` (or :class:`unittest2.TestCase` if available). t des_cryptt 6f8c114b58f2ct md5_crypts"$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.t sha512_cryptsx$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1ttests \u20AC\u00A5$s€¥$cCs#dt|jddkrdSdS(Ntos_cryptRRt((RRGR*(R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytforbidden_charactersscCs?|j}|j}t|dr;|d|jf7}n|S(NRMs (%s backend)(RGRRBRM(ReRGR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s   ccsyx"|jD]\}}||fVq Wx%|jD]\}}}||fVq/Wx%|jD]\}}}||fVqWWdS(s*iterate through known (secret, hash) pairsN(tknown_correct_hashestknown_correct_configstknown_alternate_hashes(Rtsecretthashtconfigtalt((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytiter_known_hashess cCs%t|j}|jj|S(s#test random sample secret/hash pair(RR,Rtchoice(Retknown((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_sample_hash#scCs|j||}|j|tkp-|tkd|f|jjsM|r|sWdS|spd||f}n|j|n2|rdS|sd||f}n|j|dS(s>helper to check verify() outcome, honoring is_disabled_handlers'verify() returned non-boolean value: %rNs4verify incorrectly returned True: secret=%r, hash=%rs!verify failed: secret=%r, hash=%r(t do_verifyt assertTrueR>R=RGt is_disabledR(ReR(R)RtnegateR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt check_verify+scCs!|j|td||fdS(Ns'%s() failed to return native string: %r(RRr(ReRt func_name((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcheck_returned_native_str>s cCs|j}d|jkrd|kr|j}|j}tddr[td||d}td|||dtupdateR RRGtencrypttusingR)(ReR(t use_encryptRGtcontexttsettingsR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt do_encrypt^s    "cKs.|j||}|p|jj|||S(scall handler's verify method(R>RGtverify(ReR(R)RGRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR0pscCs|jj|S(scall handler's identify method(RGtidentify(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt do_identifyuscKs|j||jj|S(s6call handler's genconfig method with specified options(R=RGt genconfig(ReRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt do_genconfigys cKs(|j||}|jj|||S(s4call handler's genhash method with specified options(R>RGtgenhash(ReR(R*RY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt do_genhash~scKsf|p |jj|}|dkr-i}n|jd|}t||j||SWdQXdS(s return sample hash for handler, w/o caring if digest is valid (uses some monkeypatching to minimize digest calculation cost) RwN(RGRAR*R>RiR)(ReRGRCRDR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytdo_stub_encrypts    sbackend not availablecCsD|j}t|| r*td r*dS|j|r=dS|jS(s helper for create_backend_case() -- returns reason to skip backend, or None if backend should be tested R8s$only default backend is being testedN(RGRQR RSR*tBACKEND_NOT_AVAILABLE(RRORG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_get_skip_backend_reasons  c Cs|j}|j}t|ds-td||jksOtd|f|f}|dkrt|tf7}ntd||f|tdd||fd|d |j}|j |}|rt ||}n|S( NRRs0handler must support uh.HasManyBackends protocolsunknown backend: %rR"s %s_%s_testRs%s (%s backend)ROR( RGRRBRRRt OsCryptMixinR_RRROR (RRORGRtbasestsubclst skip_reason((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytcreate_backend_cases$  "   cCstt|j|j}|j}|rrt|dsItdn|j|j|j |j|nddl m }|j |d|j ddS(NRNs)handler doesn't support multiple backendsi(thandlersRssalt generator(RR#RRGRORBt RuntimeErrorRRNRMRRURR(ReRGRORU((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs  cs|jfd}|d}|j|d|j|td|j|j|kd|jtjd|d|f|d}|j|dk d |j|td |d }|j|dk d |j|td dS(svalidate required attributescst|dS(N(RR*(R(RG(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytgasRsname not defined:sname must be native strsname not lower-case:s ^[a-z0-9_]+$s&name must be alphanum + underscore: %rRCssetting_kwds must be defined:ssetting_kwds must be a tuple:t context_kwdsscontext_kwds must be defined:scontext_kwds must be a tuple:N( RGR1RRrR|RxtmatchR*R(ReRWRRDRC((RGs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_01_required_attributess    cCsr|j}|j|d|jd|}|j|d|jd||j|j|d|fdS(stest basic config-string workflow this tests that genconfig() returns the expected types, and that identify() and genhash() handle the result correctly. RItstubRKRws4identify() failed to identify genconfig() output: %rN(RJR6RLR0R1RH(ReR*R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_02_config_workflows  cCs?|j}|j}|j|||j|j|jdS(stest basic using() workflowN(RGRAt assertIsNotRR(ReRGRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_02_using_workflows  c Cszd}xm|jD]b}|j|d|}|j|d|j|||j||dt|j||}|j|d|jjr|jr|j ||d|||fn |j ||d|||f|j||}|j|d|jjr9|j r9|j ||d||||fn#|j ||d ||||f|j |j |qWd S( stest basic hash-string workflow. this tests that hash()'s hashes are accepted by verify() and identify(), and regenerated correctly by genhash(). the test is run against a couple of different stock passwords. R[RBR)R3RKsBgenhash() failed to salt result hash: secret=%r hash=%r: result=%rs@genhash() failed to reproduce hash: secret=%r hash=%r: result=%rsYgenhash() failed to reproduce disabled-hash: secret=%r hash=%r other_secret=%r: result=%rsGgenhash() duplicated hash: secret=%r hash=%r wrong_secret=%r: result=%rN( tstock_passwordsRER6R4R>RLRGR2tdisabled_contains_salttassertNotEqualRR1RH(Ret use_16_legacyt wrong_secretR(Rtother((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_03_hash_workflow"s*cCs|jdtdS(sEtest hash-string workflow with legacy .encrypt() & .genhash() methodsRbN(ReR>(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_03_legacy_hash_workflowYscCs=|jtd}|j|d|jdt||jtdt||jdt|}|j|d|jjr|jr|j||n|j |||jtdt|}|j|d|jjr |jr |j||n|j |||j |j t|dS(s#test hashes can be unicode or bytesR[R)RKN( RERvR6R4RLRGR2R`RaRR1RH(ReRRd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_04_hash_types]scCs|j}t|ds*|jdn|j|j|jx|jD]}|j|t|j |t d|f|j |}|t kr|j||j |j|qM|tkr|jt|j|qMtd||fqMWdS(stest multi-backend supportRNshandler only has one backendsinvalid backend name: %rs*has_backend(%r) returned invalid value: %rN(RGRBRRRNRMRRRRrt assertNotIntRESERVED_BACKEND_NAMESRSR>RR=RR R(ReRGROtret((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_05_backendss"      cCs(d|jjkr$|jdndS(Ntsaltshandler doesn't have salt(RGRCR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt require_saltscCs/|jt|js+|jdndS(Ns!handler doesn't provide salt info(RmRRGR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_salt_infos c Cs|j|j}|j}|jd k }|rO|jdkrO|dn|jdkrm|dn|r|j|jkr|dn|j|jkr|dn|r|j|jkr|dnd|jkr| s|j|jkrtd |j fn|j rx|j s<|d nxQ|j D]+}||j krF|d |fqFqFWn|j s|d nd S(s!validate optional salt attributesismax_salt_chars must be >= 1ismin_salt_chars must be >= 0s(min_salt_chars must be <= max_salt_charss*default_salt_size must be >= min_salt_sizes*default_salt_size must be <= max_salt_sizet salt_sizesT%s: hash handler supports range of salt sizes, but doesn't offer 'salt_size' settings$default_salt_chars must not be emptysEdefault_salt_chars must be subset of salt_chars: %r not in salt_charss;default_salt_chars MUST be specified if salt_chars is emptyN( RnRRGt max_salt_sizeR*t min_salt_sizetdefault_salt_sizeRCRRt salt_charstdefault_salt_chars(ReRRtmx_settc((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt test_10_optional_salt_attributess2   (   cCs[|j}t|s(td|jddlm}t|j|t|j dS(s%calculate number of salt bits in hashsneed explicit bit-size for i(Ri( RGRRRRRRRrRRt(ReRGR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt salt_bitss   csVjtddjfd}|j|fddS(s4test hash() / genconfig() creates new salt each timeiii csS|}x-tD]}|}||krdSqWjdfdS(Ns.failed to find different salt after %d samples(RR(Rtvalue1R2tvalue2(tsamplesRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytsamplers    cs jdS(NR[(RE((Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytsNi(RmR?RxRJ(ReR|((R{Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_11_unique_salts   cCs|j|j}|jdd!}|j}||}|jd||jdd||dkr|jt|jd|d n|jt|jdd|ddS(s.test hash() / genconfig() honors min_salt_sizeiiRlR[RoiN(RnRGRsRqRJRERt ValueError(ReRGt salt_chartmin_sizets1((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_12_min_salt_sizes     c Cs|j|j}|j}|jdd!}|d ksD|d kr|d}|jd|}|jd||}|j|||jddn||}|jd|}|jd|||}|jt|jd||jt|jd|dt |rUt j dt |jd|dt }Wd QX|j ||n|j|kr|jd|d }|j||nd S( s.test hash() / genconfig() honors max_salt_sizeiiiiRlRoRRANii(RnRGRpRsR*RMRaRRRHRRR>RRq( ReRGtmax_sizeRRtc1tc2ts2tc3((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_13_max_salt_sizes.       cCs/|jr+ddlm}|j|}n|S(sprepare generated salti(tbcrypt64(tfuzz_salts_need_bcrypt_repairtpasslib.utils.binaryRt repair_unused(ReRlR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt prepare_saltQs c Cs!|j|j}|j}|j}|j}t|t}x`t||pOdD]I}t||kr}t ||}n|j |}|j d|qSWt d}|r|j d}nt|d}xG|D]?} | |kr|jt|j d| |dd| fqqWdS( stest hash() honors salt_charsi Rltslatin-1iRsinvalid salt char %r:N(RnRGRpRqRsR\tbytesRRRRRMRRkR?RR( ReRGtmxR:tcstrawRlRutchunkRv((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_14_salt_charsXs&        cCs!t|jdtrtStSdS(s)hack to determine salt keyword's datatypet_salt_is_bytesN(RRGR=RR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt salt_typessc Cs|j|j}t|jddp+d}dtfdY}|jt|jdd||tk r|jt|jddt d|n|t kpt o|tks|jt|jddd|nd S( stest non-string salt valuesRqiitfakecBseZRS((RR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRsR[RltxN( RmRRRGtobjectRRRERRRR(ReRRoR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_15_salt_type|s   )c Cs|j|j}|j}|j}|j}|jt|jdd|jt g|jdddt }WdQX|j |j||r|jt|jd|d|jt g!|jd|ddt }WdQX|j |j|n||kr|jd|d}|j |j|d|j |j||jd|d}|j |j|d|j |j|n||kr|}n |d}|jdt |}|j |j||jt|jdt |d|jd|}|j |j|dS( s$Handler.using() -- default_salt_sizeRriRANiitxxxRo( RnRGRqRpRrRRRARRR>RRr(ReRGR:RR;ttemptref((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_using_salt_sizes:     "    #cCs%t|js!|jdndS(Nshandler lacks rounds attributes(RRGR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_rounds_infoscCs|j|j}|j}|jd kr:|dn|jdkrX|dn|jdkrv|dn|j|jkr|dn|jd k r|j|jkr|dn|j|jkr|dqn|jtkr|d |jfnd S( s#validate optional rounds attributessmax_rounds not specifiedismax_rounds must be >= 1ismin_rounds must be >= 0s min_rounds must be <= max_roundss$default_rounds must be >= min_roundss$default_rounds must be <= max_roundss unknown rounds cost constant: %rN( RRGRt max_roundsR*RdR9R7R(ReRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt"test_20_optional_rounds_attributess$   cCs|j|j}|j}|jd||jdd||jt|jd|d|jt|jdd|ddS(s+test hash() / genconfig() honors min_roundsRIR[iN(RRGRdRJRERR(ReRGRd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_21_min_roundss   cCs|j|j}|j}|dk rh|jt|jd|d|jt|jdd|dn|dkr|jddn|jd|dS(s+test hash() / genconfig() honors max_roundsRIiR[iNIi( RRGRR*RRRJRERM(ReRGR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_21b_max_roundss    # c s?|j|j}|jdkrO||j}tfd|_n|j}|j}|j}|psd|d}||kr|d7}n||d}|pd|d}|jdkr|dO}|dO}|dO}d}nd}|j g#|jd|d|d|} Wd QX|| ||||fS( sU setup test helpers for testing handler.using()'s rounds parameters. t bsdi_cryptcst|jS(N(Rt_generate_rounds(R(t orig_handler(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR}si'iitmin_desired_roundstmax_desired_roundsR9N( RRGRRAt classmethodRRdRR9R( ReRGtorig_min_roundstorig_max_roundstorig_default_roundstmediumtsmalltlargetadjRR((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_create_using_rounds_helper s4             c Cs|j|j}|j}|j}|j}|j\}}}}}} |j|j||j|j||j|jd|j|j d|j|j||j|j||j|j||j|j||j|j||j|j |dS(s@ HasRounds.using() -- sanity check test harness N( RRGRdRR9RRRR*R( ReRGRRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_has_rounds_using_harness5s      c Cs|j\}}}}}}|j}|j}|j} |dkr|jt|jd|||jtg!|jd||dt } WdQX|j | j |n|r|jt|jd|||jtg!|jd||dt } WdQX|j | j |n|jg|jd||} WdQX|j | j |||jd|d|} |j | j |d||jg|jd||} WdQX|j | j |||j t ||||||j t ||||jg&|j t |||||WdQX|jd|} |j | j ||jdt |} |j | j ||jt|jdt |ddS(sF HasRounds.using() -- min_rounds / min_desired_rounds iRRANiRdR(RRdRR9RRRARRR>RRRLRr( ReRGRRRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt"test_has_rounds_using_w_min_roundsOs>    ""!'c Cs|j\}}}}}}|j}|j}|dkr|jt|jd|||jtg!|jd||dt} WdQX|j | j |n|r|jt|jd|||jtg!|jd||dt} WdQX|j | j |n|jt g|jd||} WdQX|j | j ||jt|jd||d|||jd|d|} |j | j |d||jg|jd||} WdQX|j | j |||j t ||||||j t ||||jg&|j t |||||WdQX|jd|} |j | j ||jdt|} |j | j ||jt|jdt|ddS( sF HasRounds.using() -- max_rounds / max_desired_rounds iRRANRiRR(RRdRRRRARRR>RRRRRLRr( ReRGRRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt$test_has_rounds_replace_w_max_roundssB   ""  !'c CsM|j\}}}}}}|j}|jd||}|j|j|||jd||}|j|j|||jt|jd|||r|jt|jd||n|jt|||jt||||||jdt|}|j|j||jt|jdt|ddS(s5 HasRounds.using() -- default_rounds RdRR9RN( RRRARR9RRRLRr( ReRGRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt&test_has_rounds_using_w_default_roundss  !c Cs|j\}}}}}}|j}|jd||}|j|j|||j|j|||j|j|||jd|dd||d|d||}|j|j|||j|j||j|j||dS(s- HasRounds.using() -- rounds RIiRdR9RN(RRRARRR9R( ReRGRRRRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_has_rounds_using_w_roundss cs|j\}}}}}fd}|j|dd|j|dd|j|dd|j|dd|j|dd|jt|d|jt|dd S( s: HasRounds.using() -- vary_rounds parsing csjd|jS(Nt vary_rounds(RAR(R{(RR(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytparsesg?s0.1s10%it1000gg?N(RRRR(ReRGRRRRR((RRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt+test_has_rounds_using_w_vary_rounds_parsingsc szj\}}}}}dfd}|d|||d|||||||||dt||dt||d|jdkr|d|||d|||d |||njd d \}}j|t||d j|t||d j|t||d j|t||ddS(s= HasRounds.using() -- vary_rounds generation cs8tfdtdD}t|t|fS(Nc3s|]}tVqdS(N(RL(R1R2(R(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pys si(tsetRR3R?(Rtseen((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytget_effective_ranges"csNjd|}|\}}j||dj||ddS(NRs"vary_rounds had wrong lower limit:s"vary_rounds had wrong upper limit:(RAR(RR|R}Rt seen_lowert seen_upper(RReRR(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytassert_rounds_range!sis0%i2R8s1%s49%s50%Rg?g?g333333?g?N(RR?R3R7RAtassertGreaterEqualtassertLessEqual( ReRGRRRRRR|R}((RReRRs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt.test_has_rounds_using_w_vary_rounds_generations  *c Cs|j\}}}}}}|jd|dd|d}|j|d|}|j|d|} |j|d|} |j|j||j|j| |j|j| |j|j||j|j| |j|j| dS(sF HasRounds.using() -- desired_rounds + needs_update() RiRRIN(RRARMt assertFalset needs_updateR1( ReRGRRRRRRRt small_hasht medium_hasht large_hash((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt&test_has_rounds_using_and_needs_update@s cCsB|j}t|t s,t|tj r>|jdndS(Ns)handler doesn't derive from HasManyIdents(RGR\R_RDREt HasManyIdentsR(ReRG((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytrequire_many_identsZs #cCs|j}|j|jd|jkx$|jD]}|j|tdq3W|jt|jdkd|j|jtd|j|j|jkd|j rxft |j D]R\}}|j|td|j|td|j||jkd |fqWn|}|j d}|j |}|d=|d|j||j t|||d t||j t|dd |d S( s$validate HasManyIdents configurationtidents!cls.ident_values must be unicode:is'cls.ident_values must have 2+ elements:s"cls.default_ident must be unicode:s9cls.default_ident must specify member of cls.ident_valuess'cls.ident_aliases keys must be unicode:s)cls.ident_aliases values must be unicode:s:cls.ident_aliases must map to cls.ident_values members: %rRJtxXxN(RGRR1RCt ident_valuesRRRt default_identt ident_aliasesRR/t parsehashRRR>R(ReRR{taliasRRGR)RY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_30_HasManyIdents_s8       cCs|j|j}|j}x:|jD]}||kr&Pq&q&Wtd||jfd}|j}|j|j||jd|}|j|j||j|j||j||||j||||jt|jdd|jd|}|j|j||j|j||jt |jd|d||j rxO|j j D];\}}|jd|}|j|j|dd|qnWndS( s=HasManyIdents.using() -- 'default_ident' and 'ident' keywordss6expected to find alternate ident: default=%r values=%rcSst|}|dtjS(NRJ(RKR>R(R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyteffective_idents RRRRs alias %r:N( RRGRRRRARRRRRtitems(ReRGt orig_identt alt_identRRRRR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_has_many_idents_usings2       cs|jjdkr/|jdjdSjsK|jjndjkrn|jjdSfd}|j |dj|j |t t |j |dt |j |t t |j |dt |j t |ddS(sH validate 'truncate_error' setting & related attributes ttruncate_errorNcsjd|jS(NR(RAR(R{(thasher(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt parse_valuesttruetfalseR(RGt truncate_sizeR*RhRCRRttruncate_verify_rejectR1RR>R=RR(ReR((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_truncate_error_settings   cCs|j}|jd k r=|j|jd|jdndd}d}|j|}|j }|j|j|||dd|d |}|j |j||d d S( sO test no password size limits enforced (if truncate_size=None) istruncate_size is setstoo many secretsiRRsverify rejected correct secretis full password not used in digestN( RGRR*RRRER2RR0R(ReRR(R+R)tverify_successt alt_secret((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_secret_wo_truncate_sizes   c CsX|j}|j}|s*|jdntj}d|jkrr|jdt}|jdt}tj }n$|j rd }|}n |}d }d}d}t ||d}|d } |d |} | d |} |j } | o|j } |s|stx||gD]}|j| d|}|j|j| |d|| |j|j| |d|d|j|j||d|| qW|r|j|d|}|j|j||d|| |j|j| |d|| |j|j| |d|n|rT|j||j|d|}|j|j|nd S( sQ test password size limits raise truncate_error (if appropriate) struncate_size not setRstoo many secretsRiiRGs truncate_size value is too largeN(RGRRR tPasswordSizeErrorRCRAR=R>tPasswordTruncateErrorRR*RR2RRRERR0RR1RR(ReRGRtsize_error_typet without_errort with_errorRbR+t long_secrett short_secrettalt_long_secrettalt_short_secrettshort_verify_successtlong_verify_successt cand_hashert short_hasht long_hashR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_secret_w_truncate_sizesb           cCsE|jtk}|jtdgk}d}d}|j|}|rq|jj rq|j|j||dn|j|j||d|j|}|r|jj r|j|j||dn|j|j||d|j||}|s|jjr.|j r.|j ||dn|j ||ddS( stest password case sensitivitys verify-onlyR!tTESTs%verify() should not be case sensitives!verify() should be case sensitives&genhash() should not be case sensitives"genhash() should be case sensitiveN( tsecret_case_insensitiveR>RERGR2R1R0RRLR`RRa(Rethash_insensitivetverify_insensitiveR|R}th1th2((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_61_secret_case_sensitivets.       cCs|jd}|jt|jd|jt|jd||jt|jd||jt|jd|jt|jd||jt|jd|dS(s&test non-string passwords are rejectediN(R/RRRER*RLR0(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_62_secret_borderscCsddlm}ddlm}dd|}|jd}|j||j||}|j|j||j||j ||j||j ||dS(s"test MAX_PASSWORD_SIZE is enforcedi(R(tMAX_PASSWORD_SIZEt.iN( t passlib.excRRRR/RRLRRRER0(ReRRR(R)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_63_large_secretscCs|j}|s!|jdntd}t|trjddlm}||}|jd}nx,|D]$}|jt |j |||qqWdS(s1test forbidden characters not allowed in passwords none listedR[i(titer_byte_charstasciiN( R$RRR\Rtpasslib.utils.compatRRkRRRE(RetcharsRbRRv((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_64_forbidden_charss    cCs|j|i}t| S(N(R>R(ReR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytis_secret_8bitscCsQtrM|jdkrMt|trMy|jdWqMtk rItSXntS(sl check if we're expecting potential verify failure due to crypt.crypt() encoding limitation R"sutf-8(RROR\RRsRtR>R=(ReR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytexpect_os_crypt_failures $ c CsL|j|jp|jdt}x |jD]\}}|j|rSt}n|j|j|d|f|j|}y|j ||d||f|j ||}|j |t d|f|j jr|jrw/n|j||d|||fWq/tk r)|s*q*q/Xq/W|sHtd|jndS(stest known hashessOtest must set at least one of 'known_correct_hashes' or 'known_correct_configs's&identify() failed to identify hash: %rs1verify() of known hash failed: secret=%r, hash=%rs,genhash() failed to return native string: %rsGgenhash() failed to reproduce known hash: secret=%r, hash=%r: result=%rs%s: no 8-bit secrets testedN(R1R%R&R=R,RR>RHRR4RLRRrRGR2R`RR Rt __class__(Retsaw8bitR(R)RR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_70_hashess0   c Cs|js|jdnx|jD]\}}}|j|j|d|f|j||d||f|j||}|j|td|f|jj r|j rq%n|j ||d||||fq%WdS(stest known alternate hashessno alternate hashes provideds0identify() failed to identify alternate hash: %rs;verify() of known alternate hash failed: secret=%r, hash=%rs,genhash() failed to return native string: %rsYgenhash() failed to normalize known alternate hash: secret=%r, alt=%r, hash=%r: result=%rN( R'RR1RHR4RLRRrRGR2R`R(ReR+R(R)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_71_alternatess   c Cs!|jjs1|j|jd|jdn|jsL|jdn|jrktjddtnx|jD]\}}}|j |j |d|f|j t |j ||dd|f|j||}|j|td |f|j||d ||||fquWd S( stest known config stringss&handler should not have config stringsshash has no settingssno config strings providedRRs5identify() failed to identify known config string: %rRs+verify() failed to reject config string: %rs,genhash() failed to return native string: %rs^genhash() failed to reproduce known hash from config: secret=%r, config=%r, hash=%r: result=%rN(RGRCRR&Rtfilter_config_warningsRRRR1RHRRR0RLRRrR(ReR*R(R)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_72_configs s(       c Cs|js|jdnx}|jD]r}|j|j|d|f|jt|jd|dd|f|jt|jd|dd|fq%WdS(s)test known unidentifiably-mangled stringssno unidentified hashes provideds?identify() incorrectly identified known unidentifiable hash: %rR[Rs:verify() failed to throw error for unidentifiable hash: %rs;genhash() failed to throw error for unidentifiable hash: %rN(tknown_unidentified_hashesRRRHRRR0RL(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_73_unidentified; s   c Cs|js|jdnx}|jD]r}|j|j|d|f|jt|jd|dd|f|jt|jd|dd|fq%WdS(s-test known identifiable-but-malformed stringssno malformed hashes provideds6identify() failed to identify known malformed hash: %rR[Rs5verify() failed to throw error for malformed hash: %rs6genhash() failed to throw error for malformed hash: %rN(tknown_malformed_hashesRR1RHRRR0RL(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_74_malformedP s   c Cs:|jr|jdn|js6|jdnx|jD]\}}||jjkr|j|j|d|f|jd||jd|}|j |t d|fq@|j |j|d||f|j t |jd|dd||f|j t |jd|dd ||fq@Wd S( stest known foreign hashessnot applicablesno foreign hashes provideds,identify() failed to identify known hash: %rR[s,genhash() failed to return native string: %rs:identify() incorrectly identified hash belonging to %s: %rRs;verify() failed to throw error for hash belonging to %s: %rs<genhash() failed to throw error for hash belonging to %s: %rN(taccepts_all_hashesRtknown_other_hashesRGRR1RHR0RLRRrRRR(ReRR)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_75_foreigne s*   cCsv|jt|jd |jt|jdd |jt|jdd |jt|jd|jt|jdd|jt|jddxtddgD]}|jr|j|j||jd||jd|}|j |dq|j |j|d|jt |jd|dd|jt |jd|ddqW|jd |jd d S( s#test non-string hashes are rejectedR[iRwRKs,identify() incorrectly identified empty hashRs$verify() failed to reject empty hashs%genhash() failed to reject empty hashs€¥$sabcN( RRRHR*R0RLRRR1R6RR(ReR)R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_76_hash_border s(   c s|jjr|jdnddlm}|j}|dkrU|jdn|jd|}d|rtjj }nd}|j d |}|j ||}t j d |j||t|d jfd |D|}||} d} x[|| krf|j} | d } | d} | d}| d}|rb||d sR(RdRDRCR sAfailed to verify against %r verifier: secret=%r config=%r hash=%rg?s\was able to verify wrong password using %s: wrong_secret=%r real_secret=%r config=%r hash=%ris!%s: %s: done; elapsed=%r count=%rN(RGR2RRRt max_fuzz_timetget_fuzz_verifiersRtcurrent_threadRRtFuzzHashGeneratorRtdebugRRRtgenerateRER>R=RRR(ReRRtmax_timet verifierst thread_nameRt generatorR-tstopRtoptsR(RdRDRR)RFRR((Rs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_77_fuzz_input sZ                   # csjdddljjr7jdnj}|dks[jdkrmjdnjdgfdfd }gt|D]}||^q}j|d }d}xM|D]E}|j ||j sqnt j d |j ||d7}qWdr_jd d|fn|rjd ||fndS(smultithreaded fuzz testing -- random password & options using multiple threads run test_77 simultaneously in multiple threads in an attempt to detect any concurrency issues (e.g. the bug fixed by pybcrypt 0.3) R8iNsnot applicableiisdisabled by test modecsRyjdtWn7tk r'n'dcd7R((tfailedt failed_lockRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRf* s cs@d|f}jdd|}|jt|j|S(NsFuzz-Thread-%dttargetR(tThreadt setDaemonR>R-(tnRtthread(RRf(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytlaunch3 s    is%s timed out after %f secondssH%d/%d threads failed concurrent fuzz testing (see error log for details)sP%d/%d threads stalled during concurrent fuzz testing (see error log for details)(RRRGR2Rtfuzz_thread_countRRRRtis_aliveRterrorRtfail(Ret thread_countR-R+tthreadsttimeouttstalledR,((R&R'ReRRfs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_78_fuzz_threading s4       %      cCsVttjjdpd}|r(|Stddr;dStddrNdSdSdS( s'amount of time to spend on fuzz testingtPASSLIB_TEST_FUZZ_TIMEiR?R6R7iiN(tfloatR$RRR (ReR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRR scCsCttjjdpd}|r(|Stddr;dSdSdS(s+number of threads for threaded fuzz testingtPASSLIB_TEST_FUZZ_THREADSiR?R6i N(RR$RRR (ReR{((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR._ s tfuzz_verifier_defaultcs|jg}x?|jD]4}t||}|dk r|j|qqWtdrtdr| rfd}x*tD]}|j||qWn|S(sreturn list of password verifiers (including external libs) used by fuzz testing. verifiers should be callable with signature ``func(password: unicode, hash: ascii str) -> ok: bool``. RRR8cs4fd}dd|_d|_|S(NcsBj}z!jj||SWdj|XdS(N(RMRNRF(R(R)t orig_backend(RORG(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s   tcheck_t_backends-backend(RR(ROR(RG(ROs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytmaker s N(RGtfuzz_verifiersRR*R RBR RW(ReRR t method_nameRR>RO((RGs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRs s  " cs8fd}jr+jd|_n d|_|S(Ncsj|||S(N(R0(R(R)R(Re(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt check_default ss-backendRe(ROR(ReRA((Res7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR: s   RcBseZdZedZdZeddddddZiZd Z d Z d Z d Z d Z dZdZdZdZRS(s helper which takes care of generating random passwords & configuration options to test hash with. separate from test class so we can create one per thread. s.qwertyASDF1234<>.@*#! \u00E1\u0259\u0411\u2113sutf-8RIt random_roundsRotrandom_salt_sizeRt random_identcCs"||_|j|_||_dS(N(R!RGR(ReR!R((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s  c sRfd}j\}}td|d|d|jd|jS(s generate random password and options for fuzz testing. :returns: `(secret, other_secret, settings_kwds, context_kwds)` csai}xT|jD]F\}}t|}t|}|dk r|||taccept_password_pairRtrandintRktpassword_encoding(ReR(RdR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRJ s    cCs |j}|jdkr%tdS|j}|jo=|j}|pId}|dksj|jdkr|jdt|ddd}n!|jdt|dd d }t||j |}|rt |t rx,t |j d |kr|d }qWn|S( s*generate random passwords for fuzz testingg-C6?Rwi?Bi2g?iiiciFisutf-8i(RRRRGRRRPR3Rtpassword_alphabetR\RRRk(ReRRGRRtsizeR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRQ s    $!cCs ||kS(s-verify fuzz pair contains different passwords((ReR(Rd((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRR7 s(RRRRRURTRRKRLRRRPRBRCRDRJRQRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s         c Cs|j}|js`|jt|d|jt|d|j|j|jdn|j}|j|tdd|j |j |dd||j j |j d}|j|}|j|tdd|j |j |dd||jtd|j|y|j|}d }Wntk rV}d }|}nX|d kr|j|tdd |j||n&|j|t|jdt||j}|jr|j||n|d kr|j||n|j|} |jr$|j| |n|j| ||j|d } |js\|d kro|j| |n|j| |d S( s.disable() / .enable() methodstdisabletenablesnot applicableRs#disable() must return native strings0identify() didn't recognize disable() result: %riscannot restore original hashs"enable() must return native stringRN(RGR2RRBR`RRWRRrR1RGRR-RtassertRaisesRegexRRXR*RRRa( ReRGtdisabled_defaultR[t disabled_stubRR0tetdisabled_default2tdisabled_stub2tdisabled_other((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_disable_and_enableC sX              N(RR(Rs"$1$dOHYPKoP$tnxS1T8Q6VVn3kpV8cN6o.(R sx$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwcelCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1(sfuzz_verifier_default(hRRRR*RGROR%R&R'R RRRR_R=RRR`R RR$R>t_HandlerCase__unittest_skiptpropertyRRR,R/R4R6R=R>RER0RHRJRLRMRNRORTRRZR\R^ReRfRgRkRmRnRwRxR~RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR R R RRRRR%R6RR.R?RR:RRR`(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR#s                 ) 7  # ,   )   6    2     +  8 < &   )   3 4 ! m &    ,  #   & . Y @  $ RPcBseZdZgZeZd ZeZdZ e Z dZ e dZdZe dZdZdZdZd Zd Zd ZRS( shelper used by create_backend_case() which adds additional features to test the os_crypt backend. * if crypt support is missing, inserts fake crypt support to simulate a working safe_crypt, to test passlib's codepath as fully as possible. * extra tests to verify non-conformant crypt implementations are handled correctly. * check that native crypt support is detected correctly for known platforms. R"cCsK|jdkst|jjds4|jntt|jdS(NR"(RORRGRSt_patch_safe_cryptRRPR(Re((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s cCsD|j}|s!t|j}n|jt|d}||fS(s return (handler, backend) pair to use for faking crypt.crypt() support for hash. backend will be None if none availabe. R"(talt_safe_crypt_handlerRKRGRMRZ(RRGt alt_backend((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_get_safe_crypt_handler_backend s   cs~|j\}}|s'tdn|jj|fd}ddlj}|j|d|t|_dS(sif crypt() doesn't support current hash alg, this patches safe_crypt() so that it transparently uses another one of the handler's backends, so that we can go ahead and test as much of code path as possible. s,handler has no available alternate backends!cs+j||}t|ts't|S(N(RKR\RrR(R(R)(t alt_handler(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt crypt_stub siNt_crypt( RfRRARNRtutilsRR>tusing_patched_crypt(ReRGReRhtmod((Rgs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRc s  cCsz|dksttt|j|}ddlm}||jkrv|rvtdro|jdrodSdSn|S(s| make sure os_crypt backend is tested when it's known os_crypt will be faked by _patch_safe_crypt() R"i(t has_cryptR8is hash not supported by os crypt()N( RRRPRORRmRNR RfR*(RROtreasonRm((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRO scsJddlj}fd|j_d_|j|dS(s patch passlib.utils.safe_crypt() so it returns mock value for duration of test. returns function whose .return_value controls what's returned. this defaults to None. iNcs'|dkrj||SjSdS(NR!(t __wrapped__t return_value(R(R*(t mock_crypt(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRq s Ri(RRjRiRoR*RpR(ReRl((Rqs7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt_use_mock_crypt s   csojdtfjfd}|dd|d |ddS(stest with faulty crypt()icsU|_jjdjjdjjddS(NR[(RpRRLRER0(R{(t exc_typesR)RqRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR!/ s s$xiiRN(R/RRr(ReR!((RsR)RqRes7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_80_faulty_crypt) s  cCs|j}d|_|jrk|jd}|jd|}|j|||j|jd|nhddl m }|j d}|j ||jd|j ||jd||j ||jd|dS(stest per-call crypt() fallbackR[i(R iN( RrR*Rpthas_os_crypt_fallbackRERLRR1R0RR R/R(ReRqRRR R)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_81_crypt_fallback; s   cCst|jdr$|jdntj}x@|jD]"\}}tj||r7Pq7q7W|jd||dkr|jd|nV||j krdS|r|j d||jj fn|j d||jj fdS(s0test platform-specific crypt() support detectionR@snot applicable to wrapperssno data for %r platformsvaried support on %r platformNs5expected %r platform would have native support for %rs;did not expect %r platform would have native support for %r( RBRGRtsystplatformtplatform_crypt_supportRxRYR*RkR1R(ReRxtpatterntstate((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_82_crypt_supportP s     csZj}js!t|dr%dSddlmjjfd}|S(stest results against OS crypt()R[i(tcryptcs5j|sdSt|}|||kS(s stdlib-cryptR (tcrypt_supports_variantR(R(R)(R}tencodingRe(s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt check_crypty sN(RGRkRBR*R}RRT(ReRGR((R}RRes7/usr/lib/python2.7/site-packages/passlib/tests/utils.pytfuzz_verifier_cryptl s  cCstS(s~ fuzzy_verified_crypt() helper -- used to determine if os crypt() supports a particular hash variant. (R>(ReR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR~ sN(RRRRyR>RuR*Rdt_OsCryptMixin__unittest_skipROR=RkRRRfRcRORrRtRvR|RR~(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyRP s"        tUserHandlerMixincBsceZdZdZeZeZeZdZ dZ dZ dZ de jfdYZRS(s(helper for handlers w/ 'user' context kwd; mixin for HandlerCase this overrides the HandlerCase test harness methods so that a username is automatically inserted to hash/verify calls. as well, passing in a pair of strings as the password will be interpreted as (secret,user) tusercCs|j}d}|j|d|j}|jr{|jt|j||jt|j|||jt|j||n-|j||j|||j||dS(stest user context keywordR[RN(RGR)t default_usert requires_userRRRKRF(ReRGtpasswordR)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyt test_80_user s   cCs|jj}|j}|jddtd|}|jrg|j|jd|d|dn"|j|jd|d|ddS(stest user case sensitivityR[RCRs!user should not be case sensitivesuser should be case sensitiveN( RR|R}RERtuser_case_insensitiveR1R0R(ReR|R}R)((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_81_user_case s   cCsx|j}|jd|dd}|jd|dd}|j|||jd|dd}|j||dS(stest user used as saltR[RtadmintrootN(RMRLRRa(ReR*RRth3((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyttest_82_user_salt s  cCsQt|tr|\}}n|js+|S|j}d|krM||d s    RcBs?eZejjjZejddedZdZ RS(Rt random_usert asdQWE123cCsK|j}|jj r,|jdkr,dSt||j|jddS(Ng?ii (RR!RRR*Rt user_alphabetRS(ReR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s ( RRR#RRLtcopyR?RRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s (RRRRR>RR=Rt _UserHandlerMixin__unittest_skipRRRR>R#R(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s   tEncodingHandlerMixincBsQeZdZeZeddedgZdejfdYZdZ RS(s helper for handlers w/ 'encoding' context kwd; mixin for HandlerCase this overrides the HandlerCase test harness methods so that an encoding can be inserted to hash/verify calls by passing in a pair of strings as the password will be interpreted as (secret,encoding) R!s \u00AC\u00BARcBseZedZRS(sqwerty1234<>.@*#! \u00AC(RRRRU(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR scCs2t|tr.|\}}|jd|n|S(sinsert encoding into kwdsR(R\Rt setdefault(ReR(RYR((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR> s ( RRRR>t$_EncodingHandlerMixin__unittest_skipRR_R#RR>(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s RcBs/eZdZdddZdZdZRS(s@catch_warnings() wrapper which clears warning registry & filterstalwayss.*cKsAtt|j|||_|r4tj|nd|_dS(N(RRRt _reset_filterRxtcompileR*t_reset_registry(Ret reset_filtertreset_registryRY((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s cCstt|j}|jr;tjtj|jn|j}|ri}|_x}t t j j D]c\}}|dksm|j| rqmnt|dd}|rm|j||<|jqmqmWn|S(Nt__warningregistry__(RRRRRt resetwarningst simplefilterRt_orig_registryRRwtmodulesRR*RYRRtclear(ReRjRztbackupRRltreg((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s    "cGs|j}|r|j}xttjjD]\}}|dks.|j| r\q.nt|dd}|r|j n|j |}|r.|dkrt |d|q|j |q.q.Wnt t|j|dS(NR(RRRRwRRR*RYRRRRR?RRR(ReRRzRRRlRRP((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR3 s  "  (RRRRRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyR s (kRt __future__RtbinasciiRt contextlibt functoolsRRRtloggingt getLoggerRRRRxR$RwRRR'RRRRRRRRtpasslibR R tpasslib.registrytregistrytpasslib.tests.backportsR t _TestCaseR R RRRRRRRRRRRRRRRRRRRtpasslib.utils.decorRtpasslib.utils.handlersRjRUREt__all__tgoogle.appenginetgooglet ImportErrorR=RR>R,R5tTICK_RESOLUTIONR;R<RRtstripR|R:R*R RHRLRQRWRZRKRctcontextmanagerRiR!R"RvRzR~RRRRiR#RPRRRR(((s7/usr/lib/python2.7/site-packages/passlib/tests/utils.pyts           (F(          !     t  a&