ftpd_test.go 120 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package ftpd_test
  15. import (
  16. "crypto/rand"
  17. "crypto/sha256"
  18. "crypto/tls"
  19. "encoding/hex"
  20. "encoding/json"
  21. "errors"
  22. "fmt"
  23. "io"
  24. "io/fs"
  25. "net"
  26. "net/http"
  27. "os"
  28. "os/exec"
  29. "path"
  30. "path/filepath"
  31. "runtime"
  32. "strconv"
  33. "testing"
  34. "time"
  35. ftpserver "github.com/fclairamb/ftpserverlib"
  36. "github.com/jlaffaye/ftp"
  37. "github.com/pquerna/otp"
  38. "github.com/pquerna/otp/totp"
  39. "github.com/rs/zerolog"
  40. "github.com/sftpgo/sdk"
  41. sdkkms "github.com/sftpgo/sdk/kms"
  42. "github.com/stretchr/testify/assert"
  43. "github.com/stretchr/testify/require"
  44. "github.com/drakkan/sftpgo/v2/common"
  45. "github.com/drakkan/sftpgo/v2/config"
  46. "github.com/drakkan/sftpgo/v2/dataprovider"
  47. "github.com/drakkan/sftpgo/v2/ftpd"
  48. "github.com/drakkan/sftpgo/v2/httpdtest"
  49. "github.com/drakkan/sftpgo/v2/kms"
  50. "github.com/drakkan/sftpgo/v2/logger"
  51. "github.com/drakkan/sftpgo/v2/mfa"
  52. "github.com/drakkan/sftpgo/v2/sftpd"
  53. "github.com/drakkan/sftpgo/v2/vfs"
  54. )
  55. const (
  56. logSender = "ftpdTesting"
  57. ftpServerAddr = "127.0.0.1:2121"
  58. sftpServerAddr = "127.0.0.1:2122"
  59. ftpSrvAddrTLS = "127.0.0.1:2124" // ftp server with implicit tls
  60. defaultUsername = "test_user_ftp"
  61. defaultPassword = "test_password"
  62. configDir = ".."
  63. osWindows = "windows"
  64. ftpsCert = `-----BEGIN CERTIFICATE-----
  65. MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
  66. RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
  67. dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
  68. OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
  69. VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
  70. IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
  71. NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
  72. 3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
  73. GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
  74. SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
  75. /8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
  76. dV4vKmHUzwK/eIx+8Ay3neE=
  77. -----END CERTIFICATE-----`
  78. ftpsKey = `-----BEGIN EC PARAMETERS-----
  79. BgUrgQQAIg==
  80. -----END EC PARAMETERS-----
  81. -----BEGIN EC PRIVATE KEY-----
  82. MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
  83. UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
  84. WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
  85. CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
  86. -----END EC PRIVATE KEY-----`
  87. caCRT = `-----BEGIN CERTIFICATE-----
  88. MIIE5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhDZXJ0
  89. QXV0aDAeFw0yMjA3MDQxNTQzMTFaFw0yNDAxMDQxNTUzMDhaMBMxETAPBgNVBAMT
  90. CENlcnRBdXRoMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4eyDJkmW
  91. D4OVYo7ddgiZkd6QQdPyLcsa31Wc9jdR2/peEabyNT8jSWteS6ouY84GRlnhfFeZ
  92. mpXgbaUJu/Z8Y/8riPxwL8XF4vCScQDMywpQnVUd6E9x2/+/uaD4p/BBswgKqKPe
  93. uDcHZn7MkD4QlquUhMElDrBUi1Dv/AVHnQ6iP4vd5Jlv0F+40jdq/8Wa7yhW7Pu5
  94. iNvPwCk8HjENBKVur/re+Acif8A2TlbCsuOnVduSQNmnWH+iZmB9upyBZtUszGS0
  95. JhUwtSnwUX/JapF70Pwte/PV3RK8cJ5FjuAPNeTyJvSuMTELFSAyCeiNynFGgyhW
  96. cqbEiPu6BURLculyVkmh4dOrhTrYZv/n3UJAhyxkdYrbh3INHmTa4izvclcuwoEo
  97. lFlJp3l77D0lIi+pbtcBV6ys7reyuxUAkBNwnpt2pWfCQoi4QYKcNbHm47c2phOb
  98. QSojQ8SsNU5bnlY2MDzkKo5DPav/i4d0HpndphUpx4f8hA0KylLevDRkMz9TAH7H
  99. uDssn0CxFOGHiveEAGGbn+doHjNWM339x/cdLbK0vuieDKby8YYcBY1JML57Dl9f
  100. rs52ySnDZbMqOb9zF66mQpC2FZoAj713xSkDSnSCUekrqgck1EA1ifxAviHt+p26
  101. JwaEDL7Lk01EEdYN4csSd1fezbCqTrG8ffUCAwEAAaNFMEMwDgYDVR0PAQH/BAQD
  102. AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPirPBPO01zUuf7xC+ds
  103. bOOY5QvAMA0GCSqGSIb3DQEBCwUAA4ICAQBUYa+ydfTPKjTN4lXyEZgchZQ+juny
  104. aMy1xosLz6Evj0us2Bwczmy6X2Zvaw/KteFlgKaU1Ex2UkU7FfAlaH0HtwTLFMVM
  105. p9nB7ZzStvg0n8zFM29SEkOFwZ9FRonxx4sY3FdvI4QvAWyDyqgOl8+Eedg0kC4+
  106. M7hxarTFmZZ7POZl8Hio592yx3asMmSCcmb7oUCKVI98qsf9fuL+LIZSpn4fE7av
  107. AiNBcOqCZ10CRnl4VSgAW2LH4oqROYdUv+me1u1YRwh7fCF/R7VjOLuaDzv0mp/g
  108. hzG9U+Yso3WV4b28MsctwUmGTK8Zc5QaANKgmI3ulkta37wN5KjrUuescHC7MqZg
  109. vN9n60801be1EoUL83KUx57Bix95YZR02Zge0gYdYTb+E2bwaZ4GMlf7cs6qmC6A
  110. ZPLR7Tffw2J4dPTcfEx3rPZ91s3MkAdPzYYGdGlbKp8RCFnezZ7rw2z57rnT0zDr
  111. LuL3Q6ADBfothoos/EBIC5ekXb9czp8gig+nJXLC6jlqcQpCLrV88oS3+8zACmx1
  112. d6tje9uuAqPgiQGddKZj4b4BlHmAMXq0PufQsZVoyzboTewZiLVCtTR9/iF7Cepg
  113. 6EVv57p61pFhPu8lNRAi0aH/po9yt+7435FGpn2kan6k9aDIVdaqeuxxITwsqJ4R
  114. WwSa13hh6yjoDQ==
  115. -----END CERTIFICATE-----`
  116. caCRL = `-----BEGIN X509 CRL-----
  117. MIICpzCBkAIBATANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDEwhDZXJ0QXV0aBcN
  118. MjIwNzA0MTU1MzU4WhcNMjQwNzAzMTU1MzU4WjAkMCICEQDZo5Q3lhxFuDUsxGNm
  119. 794YFw0yMjA3MDQxNTUzNThaoCMwITAfBgNVHSMEGDAWgBT4qzwTztNc1Ln+8Qvn
  120. bGzjmOULwDANBgkqhkiG9w0BAQsFAAOCAgEA1lK6g8qmhyY6myx8342dDuaauY03
  121. 0iojkxpasuYcytK6XRm96YqjZK9EETxsHHViVU0vCXES60D6wJ9gw4fTWn3WxEdx
  122. nIwbGyjUGHh2y+R3uQsfvwxsdYvDsTLAnOLwOo68dAHWmMDZRmgTuGNoYFxVQRGR
  123. Cn90ZR7LPLpCScclWM8FE/W1B90x3ZE8EhJiCI/WyyTh3EgshmB7A5GoDrFZfmvR
  124. dzoTKO+F9p2XjtmgfiBE3czWQysfATmbutZUbG/ZRb89u+ZEUyPoC94mg8fhNWoX
  125. 1d5G9QAkZFHp957/5QHLq9OHNfnWXoohhebjF4VWqZH7w+RtLc8t0PIog2lX4t1o
  126. 5N/xFk9akvuoyNGg/fYuJBmN162Q0MdeYfYKDGWdXxf6fpHxVr5v2JrIx6gOwubb
  127. cIKP22ZBv/PYOeFsAZ755lTl4OTFUjU5ZJEPD6pUc1daaIqfxsxu8gDZP92FZjsB
  128. zaalMbh30n2OhagSMBzSLg5rE6WmBzlQX0ZN8YrW4l2Vq6twnnFHY+UyblRZS+d4
  129. oHBaoOaxPEkLxNZ8ulzJS4B6c4D1CXOaBEf++snVzRRUOEdX3x7TvkkrLvIsm06R
  130. ux0L1zJb9LbZ/1rhuv70z/kIlD55sqYuRqu3RpgTgZuTERU//rYIqWd03Y5Qon8i
  131. VoC6Yp9DPldQJrk=
  132. -----END X509 CRL-----`
  133. client1Crt = `-----BEGIN CERTIFICATE-----
  134. MIIEITCCAgmgAwIBAgIRAJla/m/UkZMifNwG+DxFr2MwDQYJKoZIhvcNAQELBQAw
  135. EzERMA8GA1UEAxMIQ2VydEF1dGgwHhcNMjIwNzA0MTU0MzM3WhcNMjQwMTA0MTU1
  136. MzA3WjASMRAwDgYDVQQDEwdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
  137. MIIBCgKCAQEA8xM5v+2QfdzfwnNT5cl+6oEy2fZoI2YG6L6c25rG0pr+yl1IHKdM
  138. Zcvn93uat7hlbzxeOLfJRM7+QK1lLaxuppq9p+gT+1x9eG3E4X7e0pdbjrpJGbvN
  139. ji0hwDBLDWD8mHNq/SCk9FKtGnfZqrNB5BLw2uIKjJzVGXVlsjN6geBDm2hVjTSm
  140. zMr39CfLUdtvMaZhpIPJzbH+sNfp1zKavFIpmwCd77p/z0QAiQ9NaIvzv4PZDDEE
  141. MUHzmVAU6bUjD8GToXaMbRiz694SU8aAwvvcdjGexdbHnfSAfLOl2wTPPxvePncR
  142. aa656ZeZWxY9pRCItP+v43nm7d4sAyRD4QIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC
  143. A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQbwDqF
  144. aja3ifZHm6mtSeTK9IHc+zAfBgNVHSMEGDAWgBT4qzwTztNc1Ln+8QvnbGzjmOUL
  145. wDANBgkqhkiG9w0BAQsFAAOCAgEAprE/zV6u8UIH8g4Jb73wtUD/eIL3iBJ7mNYa
  146. lqwCyJrWH7/F9fcovJnF9WO1QPTeHxhoD9rlQK70GitUAeboYw611yNWDS4tDlaL
  147. sjpJKykUxBgBR7QSLZCrPtQ3fP2WvlZzLGqB28rASTLphShqTuGp4gJaxGHfbCU7
  148. mlV9QYi+InQxOICJJPebXUOwx5wYkFQWJ9qE1AK3QrWPi8QYFznJvHgkNAaMBEmI
  149. jAlggOzpveVvy8f4z3QG9o29LIwp7JvtJQs7QXL80FZK98/8US/3gONwTrBz2Imx
  150. 28ywvwCq7fpMyPgxX4sXtxphCNim+vuHcqDn2CvLS9p/6L6zzqbFNxpmMkJDLrOc
  151. YqtHE4TLWIaXpb5JNrYJgNCZyJuYDICVTbivtMacHpSwYtXQ4iuzY2nIr0+4y9i9
  152. MNpqv3W47xnvgUQa5vbTbIqo2NSY24A84mF5EyjhaNgNtDlN56+qTQ6HLZNVr6pv
  153. eUCCWnY4GkaZUEU1M8/uNtKaZKv1WA7gJxZDQHj8+R110mPtzm1C5jqg7jSjGy9C
  154. 8PhAwBqIXkVLNayFEtyZZobTxMH5qY1yFkI3sic7S9ZyXt3quY1Q1UT3liRteIm/
  155. sZHC5zEoidsHObkTeU44hqZVPkbvrfmgW01xTJjddnMPBH+yqjCCc94yCbW79j/2
  156. 7LEmxYg=
  157. -----END CERTIFICATE-----`
  158. client1Key = `-----BEGIN RSA PRIVATE KEY-----
  159. MIIEpAIBAAKCAQEA8xM5v+2QfdzfwnNT5cl+6oEy2fZoI2YG6L6c25rG0pr+yl1I
  160. HKdMZcvn93uat7hlbzxeOLfJRM7+QK1lLaxuppq9p+gT+1x9eG3E4X7e0pdbjrpJ
  161. GbvNji0hwDBLDWD8mHNq/SCk9FKtGnfZqrNB5BLw2uIKjJzVGXVlsjN6geBDm2hV
  162. jTSmzMr39CfLUdtvMaZhpIPJzbH+sNfp1zKavFIpmwCd77p/z0QAiQ9NaIvzv4PZ
  163. DDEEMUHzmVAU6bUjD8GToXaMbRiz694SU8aAwvvcdjGexdbHnfSAfLOl2wTPPxve
  164. PncRaa656ZeZWxY9pRCItP+v43nm7d4sAyRD4QIDAQABAoIBADE17zcgDWSt1s8z
  165. MgUPahZn2beu3x5rhXKRRIhhKWdx4atufy7t39WsFmZQK96OAlsmyZyJ+MFpdqf5
  166. csZwZmZsZYEcxw7Yhr5e2sEcQlg4NF0M8ce38cGa+X5DSK6IuBrVIw/kEAE2y7zU
  167. Dsk0SV63RvPJV4FoLuxcjB4rtd2c+JBduNUXQYVppz/KhsXN+9CbPbZ7wo1cB5fo
  168. Iu/VswvvW6EAxVx39zZcwSGdkss9XUktU8akx7T/pepIH6fwkm7uXSNez6GH9d1I
  169. 8qOiORk/gAtqPL1TJgConyYheWMM9RbXP/IwL0BV8U4ZVG53S8jx2XpP4OJQ+k35
  170. WYvz8JECgYEA+9OywKOG2lMiiUB1qZfmXB80PngNsz+L6xUWkrw58gSqYZIg0xyH
  171. Sfr7HBo0yn/PB0oMMWPpNfYvG8/kSMIWiVlsYz9fdsUuqIvN+Kh9VF6o2wn+gnJk
  172. sBE3KVMofcgwgLE6eMVv2MSQlBoXhGPNlCBHS1gorQdYE82dxDPBBzsCgYEA9xpm
  173. c3C9LxiVbw9ZZ5D2C+vzwIG2+ZeDwKSizM1436MAnzNQgQTMzQ20uFGNBD562VjI
  174. rHFlZYr3KCtSIw5gvCSuox0YB64Yq/WAtGZtH9JyKRz4h4juq6iM4FT7nUwM4DF9
  175. 3CUiDS8DGoqvCNpY50GvzSR5QVT1DKTZsMunh5MCgYEAyIWMq7pK0iQqtvG9/3o1
  176. 8xrhxfBgsF+kcV+MZvE8jstKRIFQY+oujCkutPTlHm3hE2PSC64L8G0Em/fRRmJO
  177. AbZUCT9YK8HdYlZYf2zix0DM4gW2RHcEV/KNYvmVn3q9rGvzLGHCqu/yVAvmuAOk
  178. mhON0Z/0W7siVjp/KtEvHisCgYA/cfTaMRkyDXLY6C0BbXPvTa7xP5z2atO2U89F
  179. HICrkxOmzKsf5VacU6eSJ8Y4T76FLcmglSD+uHaLRsw5Ggj2Zci9MswntKi7Bjb8
  180. msvr/sG3EqwxSJRXWNiLBObx1UP9EFgLfTFIB0kZuIAGmuF2xyPXXUUQ5Dpi+7S1
  181. MyUZpwKBgQDg+AIPvk41vQ4Cz2CKrQX5/uJSW4bOhgP1yk7ruIH4Djkag3ZzTnHM
  182. zA9/pLzRfz1ENc5I/WaYSh92eKw3j6tUtMJlE2AbfCpgOQtRUNs3IBmzCWrY8J01
  183. W/8bwB+KhfFxNYwvszYsvvOq51NgahYQkgThVm38UixB3PFpEf+NiQ==
  184. -----END RSA PRIVATE KEY-----`
  185. // client 2 crt is revoked
  186. client2Crt = `-----BEGIN CERTIFICATE-----
  187. MIIEITCCAgmgAwIBAgIRANmjlDeWHEW4NSzEY2bv3hgwDQYJKoZIhvcNAQELBQAw
  188. EzERMA8GA1UEAxMIQ2VydEF1dGgwHhcNMjIwNzA0MTU0MzUxWhcNMjQwMTA0MTU1
  189. MzA3WjASMRAwDgYDVQQDEwdjbGllbnQyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
  190. MIIBCgKCAQEAzNl7q7yS8MSaQs6zRbuqrsUuwEJ5ZH85vf7zHZKgOW3zNniXLOmH
  191. JdtQ3jKZQ1BCIsJFvez2GxGIMWbXaSPw4bL0J3vl5oItChsjGg34IvqcDxWuIk2a
  192. muRdMh7r1ryVs2ir2cQ5YHzI59BEpUWKQg3bD4yragdkb6BRc7lVgzCbrM1Eq758
  193. HHbaLwlsfpqOvheaum4IG113CeD/HHrw42W6g/qQWL+FHlYqV3plHZ8Bj+bhcZI5
  194. jdU4paGEzeY0a0NlnyH4gXGPjLKvPKFZHy4D6RiRlLHvHeiRyDtTu4wFkAiXxzGs
  195. E4UBbykmYUB85zgwpjaktOaoe36IM1T8CQIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC
  196. A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRdYIEk
  197. gxh+vTaMpAbqaPGRKGGBpTAfBgNVHSMEGDAWgBT4qzwTztNc1Ln+8QvnbGzjmOUL
  198. wDANBgkqhkiG9w0BAQsFAAOCAgEABSR/PbPfiNZ6FOrt91/I0g6LviwICDcuXhfr
  199. re4UsWp1kxXeS3CB2G71qXv3hswN8phG2hdsij0/FBEGUTLS3FTCmLmqmcVqPj3/
  200. 677PMFDoACBKgT5iIwpnNvdD+4ROM8JFjUwy7aTWx85a5yoPFGnB+ORMfLCYjr2S
  201. D02KFvKuSXWCjXphqJ41cFGne4oeh/JMkN0RNArm7wTT8yWCGgO1k4OON8dphuTV
  202. 48Wm6I9UBSWuLk1vcIlgb/8YWVwy9rBNmjOBDGuroL6PSmfZD+e9Etii0X2znZ+t
  203. qDpXJB7V5U0DbsBCtGM/dHaFz/LCoBYX9z6th1iPUHksUTM3RzN9L24r9/28dY/a
  204. shBpn5rK3ui/2mPBpO26wX14Kl/DUkdKUV9dJllSlmwo8Z0RluY9S4xnCrna/ODH
  205. FbhWmlTSs+odCZl6Lc0nuw+WQ2HnlTVJYBSFAGfsGQQ3pzk4DC5VynnxY0UniUgD
  206. WYPR8JEYa+BpH3rIQ9jmnOKWLtyc7lFPB9ab63pQBBiwRvWo+tZ2vybqjeHPuu5N
  207. BuKvvtu3RKKdSCnIo5Rs5zw4JYCjvlx/NVk9jtpa1lIHYHilvBmCcRX5DkE/yH/x
  208. IjEKhCOQpGR6D5Kkca9xNL7zNcat3bzLn+d7Wo4m09uWi9ifPdchxed0w5d9ihx1
  209. enqNrFI=
  210. -----END CERTIFICATE-----`
  211. client2Key = `-----BEGIN RSA PRIVATE KEY-----
  212. MIIEowIBAAKCAQEAzNl7q7yS8MSaQs6zRbuqrsUuwEJ5ZH85vf7zHZKgOW3zNniX
  213. LOmHJdtQ3jKZQ1BCIsJFvez2GxGIMWbXaSPw4bL0J3vl5oItChsjGg34IvqcDxWu
  214. Ik2amuRdMh7r1ryVs2ir2cQ5YHzI59BEpUWKQg3bD4yragdkb6BRc7lVgzCbrM1E
  215. q758HHbaLwlsfpqOvheaum4IG113CeD/HHrw42W6g/qQWL+FHlYqV3plHZ8Bj+bh
  216. cZI5jdU4paGEzeY0a0NlnyH4gXGPjLKvPKFZHy4D6RiRlLHvHeiRyDtTu4wFkAiX
  217. xzGsE4UBbykmYUB85zgwpjaktOaoe36IM1T8CQIDAQABAoIBAETHMJK0udFE8VZE
  218. +EQNgn0zj0LWDtQDM2vrUc04Ebu2gtZjHr7hmZLIVBqGepbzN4FcIPZnvSnRdRzB
  219. HsoaWyIsZ3VqUAJY6q5d9iclUY7M/eDCsripvaML0Y6meyCaKNkX57sx+uG+g+Xx
  220. M1saQhVzeX17CYKMANjJxw9HxsJI0aBPyiBbILHMwfRfsJU8Ou72HH1sIQuPdH2H
  221. /c9ru8YZAno6oVq1zuC/pCis+h50U9HzTnt3/4NNS6cWG/y2YLztCvm9uGo4MTd/
  222. mA9s4cxVhvQW6gCDHgGn6zj661OL/d2rpak1eWizhZvZ8jsIN/sM87b0AJeVT4zH
  223. 6xA3egECgYEA1nI5EsCetQbFBp7tDovSp3fbitwoQtdtHtLn2u4DfvmbLrgSoq0Z
  224. L+9N13xML/l8lzWai2gI69uA3c2+y1O64LkaiSeDqbeBp9b6fKMlmwIVbklEke1w
  225. XVTIWOYTTF5/8+tUOlsgme5BhLAWnQ7+SoitzHtl5e1vEYaAGamE2DECgYEA9Is2
  226. BbTk2YCqkcsB7D9q95JbY0SZpecvTv0rLR+acz3T8JrAASdmvqdBOlPWc+0ZaEdS
  227. PcJaOEw3yxYJ33cR/nLBaR2/Uu5qQebyPALs3B2pjjTFdGvcpeFxO55fowwsfR/e
  228. 0H+HeiFj5Y4S+kFWT+3FRmJ6GUB828LJYaVhQ1kCgYEA1bdsTdYN1Vfzz89fbZnH
  229. zQLUl6UlssfDhm6mhzeh4E+eaocke1+LtIwHxfOocj9v/bp8VObPzU8rNOIxfa3q
  230. lr+jRIFO5DtwSfckGEb32W3QMeNvJQe/biRqrr5NCVU8q7kibi4XZZFfVn+vacNh
  231. hqKEoz9vpCBnCs5CqFCbhmECgYAG8qWYR+lwnI08Ey58zdh2LDxYd6x94DGh5uOB
  232. JrK2r30ECwGFht8Ob6YUyCkBpizgn5YglxMFInU7Webx6GokdpI0MFotOwTd1nfv
  233. aI3eOyGEHs+1XRMpy1vyO6+v7DqfW3ZzKgxpVeWGsiCr54tSPgkq1MVvTju96qza
  234. D17SEQKBgCKC0GjDjnt/JvujdzHuBt1sWdOtb+B6kQvA09qVmuDF/Dq36jiaHDjg
  235. XMf5HU3ThYqYn3bYypZZ8nQ7BXVh4LqGNqG29wR4v6l+dLO6odXnLzfApGD9e+d4
  236. 2tmlLP54LaN35hQxRjhT8lCN0BkrNF44+bh8frwm/kuxSd8wT2S+
  237. -----END RSA PRIVATE KEY-----`
  238. testFileName = "test_file_ftp.dat"
  239. testDLFileName = "test_download_ftp.dat"
  240. tlsClient1Username = "client1"
  241. tlsClient2Username = "client2"
  242. httpFsPort = 23456
  243. defaultHTTPFsUsername = "httpfs_ftp_user"
  244. )
  245. var (
  246. allPerms = []string{dataprovider.PermAny}
  247. homeBasePath string
  248. hookCmdPath string
  249. extAuthPath string
  250. preLoginPath string
  251. postConnectPath string
  252. preDownloadPath string
  253. preUploadPath string
  254. logFilePath string
  255. caCrtPath string
  256. caCRLPath string
  257. )
  258. func TestMain(m *testing.M) {
  259. logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
  260. bannerFileName := "banner_file"
  261. bannerFile := filepath.Join(configDir, bannerFileName)
  262. logger.InitLogger(logFilePath, 5, 1, 28, false, false, zerolog.DebugLevel)
  263. err := os.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
  264. if err != nil {
  265. logger.ErrorToConsole("error creating banner file: %v", err)
  266. }
  267. // we run the test cases with UploadMode atomic and resume support. The non atomic code path
  268. // simply does not execute some code so if it works in atomic mode will
  269. // work in non atomic mode too
  270. os.Setenv("SFTPGO_COMMON__UPLOAD_MODE", "2")
  271. os.Setenv("SFTPGO_DATA_PROVIDER__CREATE_DEFAULT_ADMIN", "1")
  272. os.Setenv("SFTPGO_DEFAULT_ADMIN_USERNAME", "admin")
  273. os.Setenv("SFTPGO_DEFAULT_ADMIN_PASSWORD", "password")
  274. err = config.LoadConfig(configDir, "")
  275. if err != nil {
  276. logger.ErrorToConsole("error loading configuration: %v", err)
  277. os.Exit(1)
  278. }
  279. providerConf := config.GetProviderConf()
  280. logger.InfoToConsole("Starting FTPD tests, provider: %v", providerConf.Driver)
  281. commonConf := config.GetCommonConfig()
  282. homeBasePath = os.TempDir()
  283. if runtime.GOOS != osWindows {
  284. commonConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  285. commonConf.Actions.Hook = hookCmdPath
  286. hookCmdPath, err = exec.LookPath("true")
  287. if err != nil {
  288. logger.Warn(logSender, "", "unable to get hook command: %v", err)
  289. logger.WarnToConsole("unable to get hook command: %v", err)
  290. }
  291. }
  292. certPath := filepath.Join(os.TempDir(), "test_ftpd.crt")
  293. keyPath := filepath.Join(os.TempDir(), "test_ftpd.key")
  294. caCrtPath = filepath.Join(os.TempDir(), "test_ftpd_ca.crt")
  295. caCRLPath = filepath.Join(os.TempDir(), "test_ftpd_crl.crt")
  296. err = writeCerts(certPath, keyPath, caCrtPath, caCRLPath)
  297. if err != nil {
  298. os.Exit(1)
  299. }
  300. err = common.Initialize(commonConf, 0)
  301. if err != nil {
  302. logger.WarnToConsole("error initializing common: %v", err)
  303. os.Exit(1)
  304. }
  305. err = dataprovider.Initialize(providerConf, configDir, true)
  306. if err != nil {
  307. logger.ErrorToConsole("error initializing data provider: %v", err)
  308. os.Exit(1)
  309. }
  310. httpConfig := config.GetHTTPConfig()
  311. httpConfig.Initialize(configDir) //nolint:errcheck
  312. kmsConfig := config.GetKMSConfig()
  313. err = kmsConfig.Initialize()
  314. if err != nil {
  315. logger.ErrorToConsole("error initializing kms: %v", err)
  316. os.Exit(1)
  317. }
  318. mfaConfig := config.GetMFAConfig()
  319. err = mfaConfig.Initialize()
  320. if err != nil {
  321. logger.ErrorToConsole("error initializing MFA: %v", err)
  322. os.Exit(1)
  323. }
  324. httpdConf := config.GetHTTPDConfig()
  325. httpdConf.Bindings[0].Port = 8079
  326. httpdtest.SetBaseURL("http://127.0.0.1:8079")
  327. ftpdConf := config.GetFTPDConfig()
  328. ftpdConf.Bindings = []ftpd.Binding{
  329. {
  330. Port: 2121,
  331. ClientAuthType: 2,
  332. CertificateFile: certPath,
  333. CertificateKeyFile: keyPath,
  334. },
  335. }
  336. ftpdConf.PassivePortRange.Start = 0
  337. ftpdConf.PassivePortRange.End = 0
  338. ftpdConf.BannerFile = bannerFileName
  339. ftpdConf.CACertificates = []string{caCrtPath}
  340. ftpdConf.CARevocationLists = []string{caCRLPath}
  341. ftpdConf.EnableSite = true
  342. // required to test sftpfs
  343. sftpdConf := config.GetSFTPDConfig()
  344. sftpdConf.Bindings = []sftpd.Binding{
  345. {
  346. Port: 2122,
  347. },
  348. }
  349. hostKeyPath := filepath.Join(os.TempDir(), "id_ed25519")
  350. sftpdConf.HostKeys = []string{hostKeyPath}
  351. extAuthPath = filepath.Join(homeBasePath, "extauth.sh")
  352. preLoginPath = filepath.Join(homeBasePath, "prelogin.sh")
  353. postConnectPath = filepath.Join(homeBasePath, "postconnect.sh")
  354. preDownloadPath = filepath.Join(homeBasePath, "predownload.sh")
  355. preUploadPath = filepath.Join(homeBasePath, "preupload.sh")
  356. status := ftpd.GetStatus()
  357. if status.IsActive {
  358. logger.ErrorToConsole("ftpd is already active")
  359. os.Exit(1)
  360. }
  361. go func() {
  362. logger.Debug(logSender, "", "initializing FTP server with config %+v", ftpdConf)
  363. if err := ftpdConf.Initialize(configDir); err != nil {
  364. logger.ErrorToConsole("could not start FTP server: %v", err)
  365. os.Exit(1)
  366. }
  367. }()
  368. go func() {
  369. logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
  370. if err := sftpdConf.Initialize(configDir); err != nil {
  371. logger.ErrorToConsole("could not start SFTP server: %v", err)
  372. os.Exit(1)
  373. }
  374. }()
  375. go func() {
  376. if err := httpdConf.Initialize(configDir, 0); err != nil {
  377. logger.ErrorToConsole("could not start HTTP server: %v", err)
  378. os.Exit(1)
  379. }
  380. }()
  381. waitTCPListening(ftpdConf.Bindings[0].GetAddress())
  382. waitTCPListening(httpdConf.Bindings[0].GetAddress())
  383. waitTCPListening(sftpdConf.Bindings[0].GetAddress())
  384. ftpd.ReloadCertificateMgr() //nolint:errcheck
  385. ftpdConf = config.GetFTPDConfig()
  386. ftpdConf.Bindings = []ftpd.Binding{
  387. {
  388. Port: 2124,
  389. TLSMode: 2,
  390. },
  391. }
  392. ftpdConf.CertificateFile = certPath
  393. ftpdConf.CertificateKeyFile = keyPath
  394. ftpdConf.CACertificates = []string{caCrtPath}
  395. ftpdConf.CARevocationLists = []string{caCRLPath}
  396. ftpdConf.EnableSite = false
  397. ftpdConf.DisableActiveMode = true
  398. ftpdConf.CombineSupport = 1
  399. ftpdConf.HASHSupport = 1
  400. go func() {
  401. logger.Debug(logSender, "", "initializing FTP server with config %+v", ftpdConf)
  402. if err := ftpdConf.Initialize(configDir); err != nil {
  403. logger.ErrorToConsole("could not start FTP server: %v", err)
  404. os.Exit(1)
  405. }
  406. }()
  407. waitTCPListening(ftpdConf.Bindings[0].GetAddress())
  408. waitNoConnections()
  409. startHTTPFs()
  410. exitCode := m.Run()
  411. os.Remove(logFilePath)
  412. os.Remove(bannerFile)
  413. os.Remove(extAuthPath)
  414. os.Remove(preLoginPath)
  415. os.Remove(postConnectPath)
  416. os.Remove(preDownloadPath)
  417. os.Remove(preUploadPath)
  418. os.Remove(certPath)
  419. os.Remove(keyPath)
  420. os.Remove(caCrtPath)
  421. os.Remove(caCRLPath)
  422. os.Remove(hostKeyPath)
  423. os.Remove(hostKeyPath + ".pub")
  424. os.Exit(exitCode)
  425. }
  426. func TestInitializationFailure(t *testing.T) {
  427. ftpdConf := config.GetFTPDConfig()
  428. ftpdConf.Bindings = []ftpd.Binding{}
  429. ftpdConf.CertificateFile = filepath.Join(os.TempDir(), "test_ftpd.crt")
  430. ftpdConf.CertificateKeyFile = filepath.Join(os.TempDir(), "test_ftpd.key")
  431. err := ftpdConf.Initialize(configDir)
  432. require.EqualError(t, err, common.ErrNoBinding.Error())
  433. ftpdConf.Bindings = []ftpd.Binding{
  434. {
  435. Port: 0,
  436. },
  437. {
  438. Port: 2121,
  439. },
  440. }
  441. ftpdConf.BannerFile = "a-missing-file"
  442. err = ftpdConf.Initialize(configDir)
  443. require.Error(t, err)
  444. ftpdConf.BannerFile = ""
  445. ftpdConf.Bindings[1].TLSMode = 10
  446. err = ftpdConf.Initialize(configDir)
  447. require.Error(t, err)
  448. ftpdConf.CertificateFile = ""
  449. ftpdConf.CertificateKeyFile = ""
  450. ftpdConf.Bindings[1].TLSMode = 1
  451. err = ftpdConf.Initialize(configDir)
  452. require.Error(t, err)
  453. certPath := filepath.Join(os.TempDir(), "test_ftpd.crt")
  454. keyPath := filepath.Join(os.TempDir(), "test_ftpd.key")
  455. ftpdConf.CertificateFile = certPath
  456. ftpdConf.CertificateKeyFile = keyPath
  457. ftpdConf.CACertificates = []string{"invalid ca cert"}
  458. err = ftpdConf.Initialize(configDir)
  459. require.Error(t, err)
  460. ftpdConf.CACertificates = nil
  461. ftpdConf.CARevocationLists = []string{""}
  462. err = ftpdConf.Initialize(configDir)
  463. require.Error(t, err)
  464. ftpdConf.CACertificates = []string{caCrtPath}
  465. ftpdConf.CARevocationLists = []string{caCRLPath}
  466. ftpdConf.Bindings[1].ForcePassiveIP = "127001"
  467. err = ftpdConf.Initialize(configDir)
  468. require.Error(t, err)
  469. require.Contains(t, err.Error(), "the provided passive IP \"127001\" is not valid")
  470. ftpdConf.Bindings[1].ForcePassiveIP = ""
  471. err = ftpdConf.Initialize(configDir)
  472. require.Error(t, err)
  473. }
  474. func TestBasicFTPHandling(t *testing.T) {
  475. u := getTestUser()
  476. u.QuotaSize = 6553600
  477. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  478. assert.NoError(t, err)
  479. u = getTestSFTPUser()
  480. u.QuotaSize = 6553600
  481. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  482. assert.NoError(t, err)
  483. for _, user := range []dataprovider.User{localUser, sftpUser} {
  484. client, err := getFTPClient(user, true, nil)
  485. if assert.NoError(t, err) {
  486. if user.Username == defaultUsername {
  487. assert.Len(t, common.Connections.GetStats(), 1)
  488. } else {
  489. assert.Len(t, common.Connections.GetStats(), 2)
  490. }
  491. testFilePath := filepath.Join(homeBasePath, testFileName)
  492. testFileSize := int64(65535)
  493. expectedQuotaSize := testFileSize
  494. expectedQuotaFiles := 1
  495. err = createTestFile(testFilePath, testFileSize)
  496. assert.NoError(t, err)
  497. err = checkBasicFTP(client)
  498. assert.NoError(t, err)
  499. err = ftpUploadFile(testFilePath, path.Join("/missing_dir", testFileName), testFileSize, client, 0)
  500. assert.Error(t, err)
  501. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  502. assert.NoError(t, err)
  503. // overwrite an existing file
  504. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  505. assert.NoError(t, err)
  506. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  507. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  508. assert.NoError(t, err)
  509. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  510. assert.NoError(t, err)
  511. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  512. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  513. err = client.Rename(testFileName, testFileName+"1")
  514. assert.NoError(t, err)
  515. err = client.Delete(testFileName)
  516. assert.Error(t, err)
  517. err = client.Delete(testFileName + "1")
  518. assert.NoError(t, err)
  519. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  520. assert.NoError(t, err)
  521. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  522. assert.Equal(t, expectedQuotaSize-testFileSize, user.UsedQuotaSize)
  523. curDir, err := client.CurrentDir()
  524. if assert.NoError(t, err) {
  525. assert.Equal(t, "/", curDir)
  526. }
  527. testDir := "testDir"
  528. err = client.MakeDir(testDir)
  529. assert.NoError(t, err)
  530. err = client.ChangeDir(testDir)
  531. assert.NoError(t, err)
  532. curDir, err = client.CurrentDir()
  533. if assert.NoError(t, err) {
  534. assert.Equal(t, path.Join("/", testDir), curDir)
  535. }
  536. res, err := client.List(path.Join("/", testDir))
  537. assert.NoError(t, err)
  538. assert.Len(t, res, 0)
  539. res, err = client.List(path.Join("/"))
  540. assert.NoError(t, err)
  541. if assert.Len(t, res, 1) {
  542. assert.Equal(t, testDir, res[0].Name)
  543. }
  544. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  545. assert.NoError(t, err)
  546. size, err := client.FileSize(path.Join("/", testDir, testFileName))
  547. assert.NoError(t, err)
  548. assert.Equal(t, testFileSize, size)
  549. err = client.ChangeDirToParent()
  550. assert.NoError(t, err)
  551. curDir, err = client.CurrentDir()
  552. if assert.NoError(t, err) {
  553. assert.Equal(t, "/", curDir)
  554. }
  555. err = client.Delete(path.Join("/", testDir, testFileName))
  556. assert.NoError(t, err)
  557. err = client.Delete(testDir)
  558. assert.Error(t, err)
  559. err = client.RemoveDir(testDir)
  560. assert.NoError(t, err)
  561. err = os.Remove(testFilePath)
  562. assert.NoError(t, err)
  563. err = os.Remove(localDownloadPath)
  564. assert.NoError(t, err)
  565. err = client.Quit()
  566. assert.NoError(t, err)
  567. }
  568. }
  569. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  570. assert.NoError(t, err)
  571. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  572. assert.NoError(t, err)
  573. err = os.RemoveAll(localUser.GetHomeDir())
  574. assert.NoError(t, err)
  575. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  576. assert.Eventually(t, func() bool { return common.Connections.GetClientConnections() == 0 }, 1000*time.Millisecond,
  577. 50*time.Millisecond)
  578. }
  579. func TestHTTPFs(t *testing.T) {
  580. u := getTestUserWithHTTPFs()
  581. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  582. assert.NoError(t, err)
  583. client, err := getFTPClient(user, true, nil)
  584. if assert.NoError(t, err) {
  585. err = checkBasicFTP(client)
  586. assert.NoError(t, err)
  587. testFilePath := filepath.Join(homeBasePath, testFileName)
  588. testFileSize := int64(65535)
  589. err = createTestFile(testFilePath, testFileSize)
  590. assert.NoError(t, err)
  591. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  592. assert.NoError(t, err)
  593. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  594. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  595. assert.NoError(t, err)
  596. // test a download resume
  597. data := []byte("test data")
  598. err = os.WriteFile(testFilePath, data, os.ModePerm)
  599. assert.NoError(t, err)
  600. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  601. assert.NoError(t, err)
  602. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)-5), client, 5)
  603. assert.NoError(t, err)
  604. readed, err := os.ReadFile(localDownloadPath)
  605. assert.NoError(t, err)
  606. assert.Equal(t, []byte("data"), readed, "readed data mismatch: %q", string(readed))
  607. err = os.Remove(testFilePath)
  608. assert.NoError(t, err)
  609. err = os.Remove(localDownloadPath)
  610. assert.NoError(t, err)
  611. err = client.Quit()
  612. assert.NoError(t, err)
  613. }
  614. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  615. assert.NoError(t, err)
  616. err = os.RemoveAll(user.GetHomeDir())
  617. assert.NoError(t, err)
  618. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  619. assert.Eventually(t, func() bool { return common.Connections.GetClientConnections() == 0 }, 1000*time.Millisecond,
  620. 50*time.Millisecond)
  621. }
  622. func TestListDirWithWildcards(t *testing.T) {
  623. localUser, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  624. assert.NoError(t, err)
  625. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  626. assert.NoError(t, err)
  627. for _, user := range []dataprovider.User{localUser, sftpUser} {
  628. client, err := getFTPClient(user, true, nil)
  629. if assert.NoError(t, err) {
  630. dir1 := "test.dir"
  631. dir2 := "test.dir1"
  632. err = client.MakeDir(dir1)
  633. assert.NoError(t, err)
  634. err = client.MakeDir(dir2)
  635. assert.NoError(t, err)
  636. testFilePath := filepath.Join(homeBasePath, testFileName)
  637. testFileSize := int64(65535)
  638. err = createTestFile(testFilePath, testFileSize)
  639. assert.NoError(t, err)
  640. fileName := "file[a-z]e.dat"
  641. err = ftpUploadFile(testFilePath, fileName, testFileSize, client, 0)
  642. assert.NoError(t, err)
  643. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  644. err = ftpDownloadFile(fileName, localDownloadPath, testFileSize, client, 0)
  645. assert.NoError(t, err)
  646. entries, err := client.NameList(fileName)
  647. if assert.NoError(t, err) {
  648. assert.Len(t, entries, 1)
  649. assert.Contains(t, entries, fileName)
  650. }
  651. entries, err = client.NameList(".")
  652. assert.NoError(t, err)
  653. assert.Len(t, entries, 3)
  654. entries, err = client.NameList("/test.*")
  655. if assert.NoError(t, err) {
  656. assert.Len(t, entries, 2)
  657. assert.Contains(t, entries, dir1)
  658. assert.Contains(t, entries, dir2)
  659. }
  660. entries, err = client.NameList("/*.dir?")
  661. if assert.NoError(t, err) {
  662. assert.Len(t, entries, 1)
  663. assert.Contains(t, entries, dir2)
  664. }
  665. entries, err = client.NameList("/test.???")
  666. if assert.NoError(t, err) {
  667. assert.Len(t, entries, 1)
  668. assert.Contains(t, entries, dir1)
  669. }
  670. _, err = client.NameList("/missingdir/test.*")
  671. assert.Error(t, err)
  672. _, err = client.NameList("test[-]")
  673. if assert.Error(t, err) {
  674. assert.Contains(t, err.Error(), path.ErrBadPattern.Error())
  675. }
  676. subDir := path.Join(dir1, "sub.d")
  677. err = client.MakeDir(subDir)
  678. assert.NoError(t, err)
  679. err = client.ChangeDir(path.Dir(subDir))
  680. assert.NoError(t, err)
  681. entries, err = client.NameList("sub.?")
  682. if assert.NoError(t, err) {
  683. assert.Len(t, entries, 1)
  684. assert.Contains(t, entries, path.Base(subDir))
  685. }
  686. entries, err = client.NameList("../*.dir?")
  687. if assert.NoError(t, err) {
  688. assert.Len(t, entries, 1)
  689. assert.Contains(t, entries, path.Join("../", dir2))
  690. }
  691. err = client.ChangeDir("/")
  692. assert.NoError(t, err)
  693. entries, err = client.NameList(path.Join(dir1, "sub.*"))
  694. if assert.NoError(t, err) {
  695. assert.Len(t, entries, 1)
  696. assert.Contains(t, entries, path.Join(dir1, "sub.d"))
  697. }
  698. err = client.RemoveDir(subDir)
  699. assert.NoError(t, err)
  700. err = client.RemoveDir(dir1)
  701. assert.NoError(t, err)
  702. err = client.RemoveDir(dir2)
  703. assert.NoError(t, err)
  704. err = os.Remove(testFilePath)
  705. assert.NoError(t, err)
  706. err = os.Remove(localDownloadPath)
  707. assert.NoError(t, err)
  708. err = client.Quit()
  709. assert.NoError(t, err)
  710. }
  711. }
  712. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  713. assert.NoError(t, err)
  714. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  715. assert.NoError(t, err)
  716. err = os.RemoveAll(localUser.GetHomeDir())
  717. assert.NoError(t, err)
  718. }
  719. func TestStartDirectory(t *testing.T) {
  720. startDir := "/start/dir"
  721. u := getTestUser()
  722. u.Filters.StartDirectory = startDir
  723. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  724. assert.NoError(t, err)
  725. u = getTestSFTPUser()
  726. u.Filters.StartDirectory = startDir
  727. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  728. assert.NoError(t, err)
  729. for _, user := range []dataprovider.User{localUser, sftpUser} {
  730. client, err := getFTPClient(user, true, nil)
  731. if assert.NoError(t, err) {
  732. currentDir, err := client.CurrentDir()
  733. assert.NoError(t, err)
  734. assert.Equal(t, startDir, currentDir)
  735. testFilePath := filepath.Join(homeBasePath, testFileName)
  736. testFileSize := int64(65535)
  737. err = createTestFile(testFilePath, testFileSize)
  738. assert.NoError(t, err)
  739. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  740. assert.NoError(t, err)
  741. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  742. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  743. assert.NoError(t, err)
  744. entries, err := client.List(".")
  745. assert.NoError(t, err)
  746. if assert.Len(t, entries, 1) {
  747. assert.Equal(t, testFileName, entries[0].Name)
  748. }
  749. entries, err = client.List("/")
  750. assert.NoError(t, err)
  751. if assert.Len(t, entries, 1) {
  752. assert.Equal(t, "start", entries[0].Name)
  753. }
  754. err = client.ChangeDirToParent()
  755. assert.NoError(t, err)
  756. currentDir, err = client.CurrentDir()
  757. assert.NoError(t, err)
  758. assert.Equal(t, path.Dir(startDir), currentDir)
  759. err = client.ChangeDirToParent()
  760. assert.NoError(t, err)
  761. currentDir, err = client.CurrentDir()
  762. assert.NoError(t, err)
  763. assert.Equal(t, "/", currentDir)
  764. err = os.Remove(testFilePath)
  765. assert.NoError(t, err)
  766. err = os.Remove(localDownloadPath)
  767. assert.NoError(t, err)
  768. err = client.Quit()
  769. assert.NoError(t, err)
  770. }
  771. }
  772. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  773. assert.NoError(t, err)
  774. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  775. assert.NoError(t, err)
  776. err = os.RemoveAll(localUser.GetHomeDir())
  777. assert.NoError(t, err)
  778. }
  779. func TestMultiFactorAuth(t *testing.T) {
  780. u := getTestUser()
  781. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  782. assert.NoError(t, err)
  783. configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
  784. assert.NoError(t, err)
  785. user.Password = defaultPassword
  786. user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
  787. Enabled: true,
  788. ConfigName: configName,
  789. Secret: kms.NewPlainSecret(secret),
  790. Protocols: []string{common.ProtocolFTP},
  791. }
  792. err = dataprovider.UpdateUser(&user, "", "")
  793. assert.NoError(t, err)
  794. user.Password = defaultPassword
  795. _, err = getFTPClient(user, true, nil)
  796. if assert.Error(t, err) {
  797. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  798. }
  799. passcode, err := generateTOTPPasscode(secret, otp.AlgorithmSHA1)
  800. assert.NoError(t, err)
  801. user.Password = defaultPassword + passcode
  802. client, err := getFTPClient(user, true, nil)
  803. if assert.NoError(t, err) {
  804. err = checkBasicFTP(client)
  805. assert.NoError(t, err)
  806. err := client.Quit()
  807. assert.NoError(t, err)
  808. }
  809. // reusing the same passcode should not work
  810. _, err = getFTPClient(user, true, nil)
  811. if assert.Error(t, err) {
  812. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  813. }
  814. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  815. assert.NoError(t, err)
  816. err = os.RemoveAll(user.GetHomeDir())
  817. assert.NoError(t, err)
  818. }
  819. func TestSecondFactorRequirement(t *testing.T) {
  820. u := getTestUser()
  821. u.Filters.TwoFactorAuthProtocols = []string{common.ProtocolFTP}
  822. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  823. assert.NoError(t, err)
  824. _, err = getFTPClient(user, true, nil)
  825. if assert.Error(t, err) {
  826. assert.Contains(t, err.Error(), "second factor authentication is not set")
  827. }
  828. configName, _, secret, _, err := mfa.GenerateTOTPSecret(mfa.GetAvailableTOTPConfigNames()[0], user.Username)
  829. assert.NoError(t, err)
  830. user.Password = defaultPassword
  831. user.Filters.TOTPConfig = dataprovider.UserTOTPConfig{
  832. Enabled: true,
  833. ConfigName: configName,
  834. Secret: kms.NewPlainSecret(secret),
  835. Protocols: []string{common.ProtocolFTP},
  836. }
  837. err = dataprovider.UpdateUser(&user, "", "")
  838. assert.NoError(t, err)
  839. passcode, err := generateTOTPPasscode(secret, otp.AlgorithmSHA1)
  840. assert.NoError(t, err)
  841. user.Password = defaultPassword + passcode
  842. client, err := getFTPClient(user, true, nil)
  843. if assert.NoError(t, err) {
  844. err = checkBasicFTP(client)
  845. assert.NoError(t, err)
  846. err := client.Quit()
  847. assert.NoError(t, err)
  848. }
  849. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  850. assert.NoError(t, err)
  851. err = os.RemoveAll(user.GetHomeDir())
  852. assert.NoError(t, err)
  853. }
  854. func TestLoginInvalidCredentials(t *testing.T) {
  855. u := getTestUser()
  856. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  857. assert.NoError(t, err)
  858. user.Username = "wrong username"
  859. _, err = getFTPClient(user, false, nil)
  860. if assert.Error(t, err) {
  861. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  862. }
  863. user.Username = u.Username
  864. user.Password = "wrong pwd"
  865. _, err = getFTPClient(user, false, nil)
  866. if assert.Error(t, err) {
  867. assert.Contains(t, err.Error(), dataprovider.ErrInvalidCredentials.Error())
  868. }
  869. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  870. assert.NoError(t, err)
  871. }
  872. func TestLoginNonExistentUser(t *testing.T) {
  873. user := getTestUser()
  874. _, err := getFTPClient(user, false, nil)
  875. assert.Error(t, err)
  876. }
  877. func TestLoginExternalAuth(t *testing.T) {
  878. if runtime.GOOS == osWindows {
  879. t.Skip("this test is not available on Windows")
  880. }
  881. u := getTestUser()
  882. err := dataprovider.Close()
  883. assert.NoError(t, err)
  884. err = config.LoadConfig(configDir, "")
  885. assert.NoError(t, err)
  886. providerConf := config.GetProviderConf()
  887. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  888. assert.NoError(t, err)
  889. providerConf.ExternalAuthHook = extAuthPath
  890. providerConf.ExternalAuthScope = 0
  891. err = dataprovider.Initialize(providerConf, configDir, true)
  892. assert.NoError(t, err)
  893. g := getTestGroup()
  894. g.UserSettings.Filters.DeniedProtocols = []string{common.ProtocolFTP}
  895. group, _, err := httpdtest.AddGroup(g, http.StatusCreated)
  896. assert.NoError(t, err)
  897. client, err := getFTPClient(u, true, nil)
  898. if assert.NoError(t, err) {
  899. err = checkBasicFTP(client)
  900. assert.NoError(t, err)
  901. err := client.Quit()
  902. assert.NoError(t, err)
  903. }
  904. u.Groups = []sdk.GroupMapping{
  905. {
  906. Name: group.Name,
  907. Type: sdk.GroupTypePrimary,
  908. },
  909. }
  910. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  911. assert.NoError(t, err)
  912. _, err = getFTPClient(u, true, nil)
  913. if !assert.Error(t, err) {
  914. err := client.Quit()
  915. assert.NoError(t, err)
  916. } else {
  917. assert.Contains(t, err.Error(), "protocol FTP is not allowed")
  918. }
  919. u.Groups = nil
  920. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  921. assert.NoError(t, err)
  922. u.Username = defaultUsername + "1"
  923. client, err = getFTPClient(u, true, nil)
  924. if !assert.Error(t, err) {
  925. err := client.Quit()
  926. assert.NoError(t, err)
  927. } else {
  928. assert.Contains(t, err.Error(), "invalid credentials")
  929. }
  930. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  931. assert.NoError(t, err)
  932. assert.Equal(t, defaultUsername, user.Username)
  933. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  934. assert.NoError(t, err)
  935. err = os.RemoveAll(user.GetHomeDir())
  936. assert.NoError(t, err)
  937. _, err = httpdtest.RemoveGroup(group, http.StatusOK)
  938. assert.NoError(t, err)
  939. err = dataprovider.Close()
  940. assert.NoError(t, err)
  941. err = config.LoadConfig(configDir, "")
  942. assert.NoError(t, err)
  943. providerConf = config.GetProviderConf()
  944. err = dataprovider.Initialize(providerConf, configDir, true)
  945. assert.NoError(t, err)
  946. err = os.Remove(extAuthPath)
  947. assert.NoError(t, err)
  948. }
  949. func TestPreLoginHook(t *testing.T) {
  950. if runtime.GOOS == osWindows {
  951. t.Skip("this test is not available on Windows")
  952. }
  953. u := getTestUser()
  954. err := dataprovider.Close()
  955. assert.NoError(t, err)
  956. err = config.LoadConfig(configDir, "")
  957. assert.NoError(t, err)
  958. providerConf := config.GetProviderConf()
  959. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  960. assert.NoError(t, err)
  961. providerConf.PreLoginHook = preLoginPath
  962. err = dataprovider.Initialize(providerConf, configDir, true)
  963. assert.NoError(t, err)
  964. _, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusNotFound)
  965. assert.NoError(t, err)
  966. client, err := getFTPClient(u, false, nil)
  967. if assert.NoError(t, err) {
  968. err = checkBasicFTP(client)
  969. assert.NoError(t, err)
  970. err := client.Quit()
  971. assert.NoError(t, err)
  972. }
  973. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  974. assert.NoError(t, err)
  975. // test login with an existing user
  976. client, err = getFTPClient(user, true, nil)
  977. if assert.NoError(t, err) {
  978. err = checkBasicFTP(client)
  979. assert.NoError(t, err)
  980. err := client.Quit()
  981. assert.NoError(t, err)
  982. }
  983. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, true), os.ModePerm)
  984. assert.NoError(t, err)
  985. client, err = getFTPClient(u, false, nil)
  986. if !assert.Error(t, err) {
  987. err := client.Quit()
  988. assert.NoError(t, err)
  989. }
  990. user.Status = 0
  991. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), os.ModePerm)
  992. assert.NoError(t, err)
  993. client, err = getFTPClient(u, false, nil)
  994. if !assert.Error(t, err, "pre-login script returned a disabled user, login must fail") {
  995. err := client.Quit()
  996. assert.NoError(t, err)
  997. }
  998. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  999. assert.NoError(t, err)
  1000. err = os.RemoveAll(user.GetHomeDir())
  1001. assert.NoError(t, err)
  1002. err = dataprovider.Close()
  1003. assert.NoError(t, err)
  1004. err = config.LoadConfig(configDir, "")
  1005. assert.NoError(t, err)
  1006. providerConf = config.GetProviderConf()
  1007. err = dataprovider.Initialize(providerConf, configDir, true)
  1008. assert.NoError(t, err)
  1009. err = os.Remove(preLoginPath)
  1010. assert.NoError(t, err)
  1011. }
  1012. func TestPreDownloadHook(t *testing.T) {
  1013. if runtime.GOOS == osWindows {
  1014. t.Skip("this test is not available on Windows")
  1015. }
  1016. oldExecuteOn := common.Config.Actions.ExecuteOn
  1017. oldHook := common.Config.Actions.Hook
  1018. common.Config.Actions.ExecuteOn = []string{common.OperationPreDownload}
  1019. common.Config.Actions.Hook = preDownloadPath
  1020. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1021. assert.NoError(t, err)
  1022. err = os.WriteFile(preDownloadPath, getExitCodeScriptContent(0), os.ModePerm)
  1023. assert.NoError(t, err)
  1024. testFilePath := filepath.Join(homeBasePath, testFileName)
  1025. testFileSize := int64(65535)
  1026. err = createTestFile(testFilePath, testFileSize)
  1027. assert.NoError(t, err)
  1028. client, err := getFTPClient(user, true, nil)
  1029. if assert.NoError(t, err) {
  1030. err = checkBasicFTP(client)
  1031. assert.NoError(t, err)
  1032. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1033. assert.NoError(t, err)
  1034. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1035. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1036. assert.NoError(t, err)
  1037. err := client.Quit()
  1038. assert.NoError(t, err)
  1039. err = os.Remove(localDownloadPath)
  1040. assert.NoError(t, err)
  1041. }
  1042. // now return an error from the pre-download hook
  1043. err = os.WriteFile(preDownloadPath, getExitCodeScriptContent(1), os.ModePerm)
  1044. assert.NoError(t, err)
  1045. client, err = getFTPClient(user, true, nil)
  1046. if assert.NoError(t, err) {
  1047. err = checkBasicFTP(client)
  1048. assert.NoError(t, err)
  1049. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1050. assert.NoError(t, err)
  1051. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1052. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1053. if assert.Error(t, err) {
  1054. assert.Contains(t, err.Error(), "permission denied")
  1055. }
  1056. err := client.Quit()
  1057. assert.NoError(t, err)
  1058. err = os.Remove(localDownloadPath)
  1059. assert.NoError(t, err)
  1060. }
  1061. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1062. assert.NoError(t, err)
  1063. err = os.RemoveAll(user.GetHomeDir())
  1064. assert.NoError(t, err)
  1065. err = os.Remove(testFilePath)
  1066. assert.NoError(t, err)
  1067. common.Config.Actions.ExecuteOn = oldExecuteOn
  1068. common.Config.Actions.Hook = oldHook
  1069. }
  1070. func TestPreUploadHook(t *testing.T) {
  1071. if runtime.GOOS == osWindows {
  1072. t.Skip("this test is not available on Windows")
  1073. }
  1074. oldExecuteOn := common.Config.Actions.ExecuteOn
  1075. oldHook := common.Config.Actions.Hook
  1076. common.Config.Actions.ExecuteOn = []string{common.OperationPreUpload}
  1077. common.Config.Actions.Hook = preUploadPath
  1078. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1079. assert.NoError(t, err)
  1080. err = os.WriteFile(preUploadPath, getExitCodeScriptContent(0), os.ModePerm)
  1081. assert.NoError(t, err)
  1082. testFilePath := filepath.Join(homeBasePath, testFileName)
  1083. testFileSize := int64(65535)
  1084. err = createTestFile(testFilePath, testFileSize)
  1085. assert.NoError(t, err)
  1086. client, err := getFTPClient(user, true, nil)
  1087. if assert.NoError(t, err) {
  1088. err = checkBasicFTP(client)
  1089. assert.NoError(t, err)
  1090. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1091. assert.NoError(t, err)
  1092. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1093. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1094. assert.NoError(t, err)
  1095. err := client.Quit()
  1096. assert.NoError(t, err)
  1097. err = os.Remove(localDownloadPath)
  1098. assert.NoError(t, err)
  1099. }
  1100. // now return an error from the pre-upload hook
  1101. err = os.WriteFile(preUploadPath, getExitCodeScriptContent(1), os.ModePerm)
  1102. assert.NoError(t, err)
  1103. client, err = getFTPClient(user, true, nil)
  1104. if assert.NoError(t, err) {
  1105. err = checkBasicFTP(client)
  1106. assert.NoError(t, err)
  1107. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1108. if assert.Error(t, err) {
  1109. assert.Contains(t, err.Error(), ftpserver.ErrFileNameNotAllowed.Error())
  1110. }
  1111. err = ftpUploadFile(testFilePath, testFileName+"1", testFileSize, client, 0)
  1112. if assert.Error(t, err) {
  1113. assert.Contains(t, err.Error(), ftpserver.ErrFileNameNotAllowed.Error())
  1114. }
  1115. err := client.Quit()
  1116. assert.NoError(t, err)
  1117. }
  1118. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1119. assert.NoError(t, err)
  1120. err = os.RemoveAll(user.GetHomeDir())
  1121. assert.NoError(t, err)
  1122. err = os.Remove(testFilePath)
  1123. assert.NoError(t, err)
  1124. common.Config.Actions.ExecuteOn = oldExecuteOn
  1125. common.Config.Actions.Hook = oldHook
  1126. }
  1127. func TestPostConnectHook(t *testing.T) {
  1128. if runtime.GOOS == osWindows {
  1129. t.Skip("this test is not available on Windows")
  1130. }
  1131. common.Config.PostConnectHook = postConnectPath
  1132. u := getTestUser()
  1133. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1134. assert.NoError(t, err)
  1135. err = os.WriteFile(postConnectPath, getExitCodeScriptContent(0), os.ModePerm)
  1136. assert.NoError(t, err)
  1137. client, err := getFTPClient(user, true, nil)
  1138. if assert.NoError(t, err) {
  1139. err = checkBasicFTP(client)
  1140. assert.NoError(t, err)
  1141. err := client.Quit()
  1142. assert.NoError(t, err)
  1143. }
  1144. err = os.WriteFile(postConnectPath, getExitCodeScriptContent(1), os.ModePerm)
  1145. assert.NoError(t, err)
  1146. client, err = getFTPClient(user, true, nil)
  1147. if !assert.Error(t, err) {
  1148. err := client.Quit()
  1149. assert.NoError(t, err)
  1150. }
  1151. common.Config.PostConnectHook = "http://127.0.0.1:8079/healthz"
  1152. client, err = getFTPClient(user, false, nil)
  1153. if assert.NoError(t, err) {
  1154. err = checkBasicFTP(client)
  1155. assert.NoError(t, err)
  1156. err := client.Quit()
  1157. assert.NoError(t, err)
  1158. }
  1159. common.Config.PostConnectHook = "http://127.0.0.1:8079/notfound"
  1160. client, err = getFTPClient(user, true, nil)
  1161. if !assert.Error(t, err) {
  1162. err := client.Quit()
  1163. assert.NoError(t, err)
  1164. }
  1165. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1166. assert.NoError(t, err)
  1167. err = os.RemoveAll(user.GetHomeDir())
  1168. assert.NoError(t, err)
  1169. common.Config.PostConnectHook = ""
  1170. }
  1171. //nolint:dupl
  1172. func TestMaxConnections(t *testing.T) {
  1173. oldValue := common.Config.MaxTotalConnections
  1174. common.Config.MaxTotalConnections = 1
  1175. assert.Eventually(t, func() bool {
  1176. return common.Connections.GetClientConnections() == 0
  1177. }, 1000*time.Millisecond, 50*time.Millisecond)
  1178. user := getTestUser()
  1179. err := dataprovider.AddUser(&user, "", "")
  1180. assert.NoError(t, err)
  1181. user.Password = ""
  1182. client, err := getFTPClient(user, true, nil)
  1183. if assert.NoError(t, err) {
  1184. err = checkBasicFTP(client)
  1185. assert.NoError(t, err)
  1186. _, err = getFTPClient(user, false, nil)
  1187. assert.Error(t, err)
  1188. err = client.Quit()
  1189. assert.NoError(t, err)
  1190. }
  1191. err = dataprovider.DeleteUser(user.Username, "", "")
  1192. assert.NoError(t, err)
  1193. err = os.RemoveAll(user.GetHomeDir())
  1194. assert.NoError(t, err)
  1195. common.Config.MaxTotalConnections = oldValue
  1196. }
  1197. //nolint:dupl
  1198. func TestMaxPerHostConnections(t *testing.T) {
  1199. oldValue := common.Config.MaxPerHostConnections
  1200. common.Config.MaxPerHostConnections = 1
  1201. assert.Eventually(t, func() bool {
  1202. return common.Connections.GetClientConnections() == 0
  1203. }, 1000*time.Millisecond, 50*time.Millisecond)
  1204. user := getTestUser()
  1205. err := dataprovider.AddUser(&user, "", "")
  1206. assert.NoError(t, err)
  1207. user.Password = ""
  1208. client, err := getFTPClient(user, true, nil)
  1209. if assert.NoError(t, err) {
  1210. err = checkBasicFTP(client)
  1211. assert.NoError(t, err)
  1212. _, err = getFTPClient(user, false, nil)
  1213. assert.Error(t, err)
  1214. err = client.Quit()
  1215. assert.NoError(t, err)
  1216. }
  1217. err = dataprovider.DeleteUser(user.Username, "", "")
  1218. assert.NoError(t, err)
  1219. err = os.RemoveAll(user.GetHomeDir())
  1220. assert.NoError(t, err)
  1221. common.Config.MaxPerHostConnections = oldValue
  1222. }
  1223. func TestRateLimiter(t *testing.T) {
  1224. oldConfig := config.GetCommonConfig()
  1225. cfg := config.GetCommonConfig()
  1226. cfg.DefenderConfig.Enabled = true
  1227. cfg.DefenderConfig.Threshold = 5
  1228. cfg.DefenderConfig.ScoreLimitExceeded = 3
  1229. cfg.RateLimitersConfig = []common.RateLimiterConfig{
  1230. {
  1231. Average: 1,
  1232. Period: 1000,
  1233. Burst: 1,
  1234. Type: 2,
  1235. Protocols: []string{common.ProtocolFTP},
  1236. GenerateDefenderEvents: true,
  1237. EntriesSoftLimit: 100,
  1238. EntriesHardLimit: 150,
  1239. },
  1240. }
  1241. err := common.Initialize(cfg, 0)
  1242. assert.NoError(t, err)
  1243. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1244. assert.NoError(t, err)
  1245. client, err := getFTPClient(user, false, nil)
  1246. if assert.NoError(t, err) {
  1247. err = checkBasicFTP(client)
  1248. assert.NoError(t, err)
  1249. err = client.Quit()
  1250. assert.NoError(t, err)
  1251. }
  1252. _, err = getFTPClient(user, true, nil)
  1253. if assert.Error(t, err) {
  1254. assert.Contains(t, err.Error(), "rate limit exceed")
  1255. }
  1256. _, err = getFTPClient(user, false, nil)
  1257. if assert.Error(t, err) {
  1258. assert.Contains(t, err.Error(), "rate limit exceed")
  1259. }
  1260. _, err = getFTPClient(user, true, nil)
  1261. if assert.Error(t, err) {
  1262. assert.Contains(t, err.Error(), "banned client IP")
  1263. }
  1264. err = dataprovider.DeleteUser(user.Username, "", "")
  1265. assert.NoError(t, err)
  1266. err = os.RemoveAll(user.GetHomeDir())
  1267. assert.NoError(t, err)
  1268. err = common.Initialize(oldConfig, 0)
  1269. assert.NoError(t, err)
  1270. }
  1271. func TestDefender(t *testing.T) {
  1272. oldConfig := config.GetCommonConfig()
  1273. cfg := config.GetCommonConfig()
  1274. cfg.DefenderConfig.Enabled = true
  1275. cfg.DefenderConfig.Threshold = 3
  1276. cfg.DefenderConfig.ScoreLimitExceeded = 2
  1277. err := common.Initialize(cfg, 0)
  1278. assert.NoError(t, err)
  1279. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  1280. assert.NoError(t, err)
  1281. client, err := getFTPClient(user, false, nil)
  1282. if assert.NoError(t, err) {
  1283. err = checkBasicFTP(client)
  1284. assert.NoError(t, err)
  1285. err = client.Quit()
  1286. assert.NoError(t, err)
  1287. }
  1288. for i := 0; i < 3; i++ {
  1289. user.Password = "wrong_pwd"
  1290. _, err = getFTPClient(user, false, nil)
  1291. assert.Error(t, err)
  1292. }
  1293. user.Password = defaultPassword
  1294. _, err = getFTPClient(user, false, nil)
  1295. if assert.Error(t, err) {
  1296. assert.Contains(t, err.Error(), "banned client IP")
  1297. }
  1298. err = dataprovider.DeleteUser(user.Username, "", "")
  1299. assert.NoError(t, err)
  1300. err = os.RemoveAll(user.GetHomeDir())
  1301. assert.NoError(t, err)
  1302. err = common.Initialize(oldConfig, 0)
  1303. assert.NoError(t, err)
  1304. }
  1305. func TestMaxSessions(t *testing.T) {
  1306. u := getTestUser()
  1307. u.MaxSessions = 1
  1308. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1309. assert.NoError(t, err)
  1310. client, err := getFTPClient(user, true, nil)
  1311. if assert.NoError(t, err) {
  1312. err = checkBasicFTP(client)
  1313. assert.NoError(t, err)
  1314. _, err = getFTPClient(user, false, nil)
  1315. assert.Error(t, err)
  1316. err = client.Quit()
  1317. assert.NoError(t, err)
  1318. }
  1319. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1320. assert.NoError(t, err)
  1321. err = os.RemoveAll(user.GetHomeDir())
  1322. assert.NoError(t, err)
  1323. }
  1324. func TestZeroBytesTransfers(t *testing.T) {
  1325. u := getTestUser()
  1326. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1327. assert.NoError(t, err)
  1328. for _, useTLS := range []bool{true, false} {
  1329. client, err := getFTPClient(user, useTLS, nil)
  1330. if assert.NoError(t, err) {
  1331. testFileName := "testfilename"
  1332. err = checkBasicFTP(client)
  1333. assert.NoError(t, err)
  1334. localDownloadPath := filepath.Join(homeBasePath, "empty_download")
  1335. err = os.WriteFile(localDownloadPath, []byte(""), os.ModePerm)
  1336. assert.NoError(t, err)
  1337. err = ftpUploadFile(localDownloadPath, testFileName, 0, client, 0)
  1338. assert.NoError(t, err)
  1339. size, err := client.FileSize(testFileName)
  1340. assert.NoError(t, err)
  1341. assert.Equal(t, int64(0), size)
  1342. err = os.Remove(localDownloadPath)
  1343. assert.NoError(t, err)
  1344. assert.NoFileExists(t, localDownloadPath)
  1345. err = ftpDownloadFile(testFileName, localDownloadPath, 0, client, 0)
  1346. assert.NoError(t, err)
  1347. assert.FileExists(t, localDownloadPath)
  1348. err = client.Quit()
  1349. assert.NoError(t, err)
  1350. err = os.Remove(localDownloadPath)
  1351. assert.NoError(t, err)
  1352. }
  1353. }
  1354. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1355. assert.NoError(t, err)
  1356. err = os.RemoveAll(user.GetHomeDir())
  1357. assert.NoError(t, err)
  1358. }
  1359. func TestDownloadErrors(t *testing.T) {
  1360. u := getTestUser()
  1361. u.QuotaFiles = 1
  1362. subDir1 := "sub1"
  1363. subDir2 := "sub2"
  1364. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  1365. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  1366. dataprovider.PermDelete, dataprovider.PermDownload}
  1367. u.Filters.FilePatterns = []sdk.PatternsFilter{
  1368. {
  1369. Path: "/sub2",
  1370. AllowedPatterns: []string{},
  1371. DeniedPatterns: []string{"*.jpg", "*.zip"},
  1372. },
  1373. }
  1374. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1375. assert.NoError(t, err)
  1376. client, err := getFTPClient(user, true, nil)
  1377. if assert.NoError(t, err) {
  1378. testFilePath1 := filepath.Join(user.HomeDir, subDir1, "file.zip")
  1379. testFilePath2 := filepath.Join(user.HomeDir, subDir2, "file.zip")
  1380. testFilePath3 := filepath.Join(user.HomeDir, subDir2, "file.jpg")
  1381. err = os.MkdirAll(filepath.Dir(testFilePath1), os.ModePerm)
  1382. assert.NoError(t, err)
  1383. err = os.MkdirAll(filepath.Dir(testFilePath2), os.ModePerm)
  1384. assert.NoError(t, err)
  1385. err = os.WriteFile(testFilePath1, []byte("file1"), os.ModePerm)
  1386. assert.NoError(t, err)
  1387. err = os.WriteFile(testFilePath2, []byte("file2"), os.ModePerm)
  1388. assert.NoError(t, err)
  1389. err = os.WriteFile(testFilePath3, []byte("file3"), os.ModePerm)
  1390. assert.NoError(t, err)
  1391. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1392. err = ftpDownloadFile(path.Join("/", subDir1, "file.zip"), localDownloadPath, 5, client, 0)
  1393. assert.Error(t, err)
  1394. err = ftpDownloadFile(path.Join("/", subDir2, "file.zip"), localDownloadPath, 5, client, 0)
  1395. assert.Error(t, err)
  1396. err = ftpDownloadFile(path.Join("/", subDir2, "file.jpg"), localDownloadPath, 5, client, 0)
  1397. assert.Error(t, err)
  1398. err = ftpDownloadFile("/missing.zip", localDownloadPath, 5, client, 0)
  1399. assert.Error(t, err)
  1400. err = client.Quit()
  1401. assert.NoError(t, err)
  1402. err = os.Remove(localDownloadPath)
  1403. assert.NoError(t, err)
  1404. }
  1405. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1406. assert.NoError(t, err)
  1407. err = os.RemoveAll(user.GetHomeDir())
  1408. assert.NoError(t, err)
  1409. }
  1410. func TestUploadErrors(t *testing.T) {
  1411. u := getTestUser()
  1412. u.QuotaSize = 65535
  1413. subDir1 := "sub1"
  1414. subDir2 := "sub2"
  1415. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  1416. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  1417. dataprovider.PermDelete}
  1418. u.Filters.FilePatterns = []sdk.PatternsFilter{
  1419. {
  1420. Path: "/sub2",
  1421. AllowedPatterns: []string{},
  1422. DeniedPatterns: []string{"*.zip"},
  1423. },
  1424. }
  1425. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1426. assert.NoError(t, err)
  1427. client, err := getFTPClient(user, true, nil)
  1428. if assert.NoError(t, err) {
  1429. testFilePath := filepath.Join(homeBasePath, testFileName)
  1430. testFileSize := user.QuotaSize
  1431. err = createTestFile(testFilePath, testFileSize)
  1432. assert.NoError(t, err)
  1433. err = client.MakeDir(subDir1)
  1434. assert.NoError(t, err)
  1435. err = client.MakeDir(subDir2)
  1436. assert.NoError(t, err)
  1437. err = client.ChangeDir(subDir1)
  1438. assert.NoError(t, err)
  1439. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1440. assert.Error(t, err)
  1441. err = client.ChangeDirToParent()
  1442. assert.NoError(t, err)
  1443. err = client.ChangeDir(subDir2)
  1444. assert.NoError(t, err)
  1445. err = ftpUploadFile(testFilePath, testFileName+".zip", testFileSize, client, 0)
  1446. assert.Error(t, err)
  1447. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1448. assert.NoError(t, err)
  1449. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1450. assert.Error(t, err)
  1451. err = client.ChangeDir("/")
  1452. assert.NoError(t, err)
  1453. err = ftpUploadFile(testFilePath, subDir1, testFileSize, client, 0)
  1454. assert.Error(t, err)
  1455. // overquota
  1456. err = ftpUploadFile(testFilePath, testFileName+"1", testFileSize, client, 0)
  1457. assert.Error(t, err)
  1458. err = client.Delete(path.Join("/", subDir2, testFileName))
  1459. assert.NoError(t, err)
  1460. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1461. assert.NoError(t, err)
  1462. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1463. assert.Error(t, err)
  1464. err = client.Quit()
  1465. assert.NoError(t, err)
  1466. err = os.Remove(testFilePath)
  1467. assert.NoError(t, err)
  1468. }
  1469. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1470. assert.NoError(t, err)
  1471. err = os.RemoveAll(user.GetHomeDir())
  1472. assert.NoError(t, err)
  1473. }
  1474. func TestSFTPBuffered(t *testing.T) {
  1475. u := getTestUser()
  1476. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1477. assert.NoError(t, err)
  1478. u = getTestSFTPUser()
  1479. u.QuotaFiles = 100
  1480. u.FsConfig.SFTPConfig.BufferSize = 2
  1481. u.HomeDir = filepath.Join(os.TempDir(), u.Username)
  1482. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1483. assert.NoError(t, err)
  1484. client, err := getFTPClient(sftpUser, true, nil)
  1485. if assert.NoError(t, err) {
  1486. testFilePath := filepath.Join(homeBasePath, testFileName)
  1487. testFileSize := int64(65535)
  1488. expectedQuotaSize := testFileSize
  1489. expectedQuotaFiles := 1
  1490. err = createTestFile(testFilePath, testFileSize)
  1491. assert.NoError(t, err)
  1492. err = checkBasicFTP(client)
  1493. assert.NoError(t, err)
  1494. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1495. assert.NoError(t, err)
  1496. // overwrite an existing file
  1497. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1498. assert.NoError(t, err)
  1499. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1500. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  1501. assert.NoError(t, err)
  1502. user, _, err := httpdtest.GetUserByUsername(sftpUser.Username, http.StatusOK)
  1503. assert.NoError(t, err)
  1504. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  1505. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  1506. data := []byte("test data")
  1507. err = os.WriteFile(testFilePath, data, os.ModePerm)
  1508. assert.NoError(t, err)
  1509. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  1510. assert.NoError(t, err)
  1511. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)+5), client, 5)
  1512. if assert.Error(t, err) {
  1513. assert.Contains(t, err.Error(), "operation unsupported")
  1514. }
  1515. err = ftpDownloadFile(testFileName, localDownloadPath, int64(4), client, 5)
  1516. assert.NoError(t, err)
  1517. readed, err := os.ReadFile(localDownloadPath)
  1518. assert.NoError(t, err)
  1519. assert.Equal(t, []byte("data"), readed)
  1520. // try to append to a file, it should fail
  1521. // now append to a file
  1522. srcFile, err := os.Open(testFilePath)
  1523. if assert.NoError(t, err) {
  1524. err = client.Append(testFileName, srcFile)
  1525. if assert.Error(t, err) {
  1526. assert.Contains(t, err.Error(), "operation unsupported")
  1527. }
  1528. err = srcFile.Close()
  1529. assert.NoError(t, err)
  1530. size, err := client.FileSize(testFileName)
  1531. assert.NoError(t, err)
  1532. assert.Equal(t, int64(len(data)), size)
  1533. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)), client, 0)
  1534. assert.NoError(t, err)
  1535. }
  1536. err = os.Remove(testFilePath)
  1537. assert.NoError(t, err)
  1538. err = os.Remove(localDownloadPath)
  1539. assert.NoError(t, err)
  1540. err = client.Quit()
  1541. assert.NoError(t, err)
  1542. }
  1543. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1544. assert.NoError(t, err)
  1545. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1546. assert.NoError(t, err)
  1547. err = os.RemoveAll(localUser.GetHomeDir())
  1548. assert.NoError(t, err)
  1549. err = os.RemoveAll(sftpUser.GetHomeDir())
  1550. assert.NoError(t, err)
  1551. }
  1552. func TestResume(t *testing.T) {
  1553. u := getTestUser()
  1554. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1555. assert.NoError(t, err)
  1556. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  1557. assert.NoError(t, err)
  1558. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1559. client, err := getFTPClient(user, true, nil)
  1560. if assert.NoError(t, err) {
  1561. testFilePath := filepath.Join(homeBasePath, testFileName)
  1562. data := []byte("test data")
  1563. err = os.WriteFile(testFilePath, data, os.ModePerm)
  1564. assert.NoError(t, err)
  1565. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  1566. assert.NoError(t, err)
  1567. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)+5), client, 5)
  1568. assert.NoError(t, err)
  1569. readed, err := os.ReadFile(filepath.Join(user.GetHomeDir(), testFileName))
  1570. assert.NoError(t, err)
  1571. assert.Equal(t, "test test data", string(readed))
  1572. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1573. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)), client, 5)
  1574. assert.NoError(t, err)
  1575. readed, err = os.ReadFile(localDownloadPath)
  1576. assert.NoError(t, err)
  1577. assert.Equal(t, data, readed)
  1578. err = client.Delete(testFileName)
  1579. assert.NoError(t, err)
  1580. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  1581. assert.NoError(t, err)
  1582. // now append to a file
  1583. srcFile, err := os.Open(testFilePath)
  1584. if assert.NoError(t, err) {
  1585. err = client.Append(testFileName, srcFile)
  1586. assert.NoError(t, err)
  1587. err = srcFile.Close()
  1588. assert.NoError(t, err)
  1589. size, err := client.FileSize(testFileName)
  1590. assert.NoError(t, err)
  1591. assert.Equal(t, int64(2*len(data)), size)
  1592. err = ftpDownloadFile(testFileName, localDownloadPath, int64(2*len(data)), client, 0)
  1593. assert.NoError(t, err)
  1594. readed, err = os.ReadFile(localDownloadPath)
  1595. assert.NoError(t, err)
  1596. expected := append(data, data...)
  1597. assert.Equal(t, expected, readed)
  1598. }
  1599. err = client.Quit()
  1600. assert.NoError(t, err)
  1601. err = os.Remove(testFilePath)
  1602. assert.NoError(t, err)
  1603. err = os.Remove(localDownloadPath)
  1604. assert.NoError(t, err)
  1605. if user.Username == defaultUsername {
  1606. err = os.RemoveAll(user.GetHomeDir())
  1607. assert.NoError(t, err)
  1608. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1609. assert.NoError(t, err)
  1610. user.Password = defaultPassword
  1611. user.ID = 0
  1612. user.CreatedAt = 0
  1613. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  1614. assert.NoError(t, err, string(resp))
  1615. }
  1616. }
  1617. }
  1618. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1619. assert.NoError(t, err)
  1620. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1621. assert.NoError(t, err)
  1622. err = os.RemoveAll(localUser.GetHomeDir())
  1623. assert.NoError(t, err)
  1624. }
  1625. //nolint:dupl
  1626. func TestDeniedLoginMethod(t *testing.T) {
  1627. u := getTestUser()
  1628. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  1629. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1630. assert.NoError(t, err)
  1631. _, err = getFTPClient(user, false, nil)
  1632. assert.Error(t, err)
  1633. user.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodKeyAndPassword}
  1634. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1635. assert.NoError(t, err)
  1636. client, err := getFTPClient(user, true, nil)
  1637. if assert.NoError(t, err) {
  1638. assert.NoError(t, checkBasicFTP(client))
  1639. err = client.Quit()
  1640. assert.NoError(t, err)
  1641. }
  1642. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1643. assert.NoError(t, err)
  1644. err = os.RemoveAll(user.GetHomeDir())
  1645. assert.NoError(t, err)
  1646. }
  1647. //nolint:dupl
  1648. func TestDeniedProtocols(t *testing.T) {
  1649. u := getTestUser()
  1650. u.Filters.DeniedProtocols = []string{common.ProtocolFTP}
  1651. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1652. assert.NoError(t, err)
  1653. _, err = getFTPClient(user, false, nil)
  1654. assert.Error(t, err)
  1655. user.Filters.DeniedProtocols = []string{common.ProtocolSSH, common.ProtocolWebDAV}
  1656. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1657. assert.NoError(t, err)
  1658. client, err := getFTPClient(user, true, nil)
  1659. if assert.NoError(t, err) {
  1660. assert.NoError(t, checkBasicFTP(client))
  1661. err = client.Quit()
  1662. assert.NoError(t, err)
  1663. }
  1664. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1665. assert.NoError(t, err)
  1666. err = os.RemoveAll(user.GetHomeDir())
  1667. assert.NoError(t, err)
  1668. }
  1669. func TestQuotaLimits(t *testing.T) {
  1670. u := getTestUser()
  1671. u.QuotaFiles = 1
  1672. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1673. assert.NoError(t, err)
  1674. u = getTestSFTPUser()
  1675. u.QuotaFiles = 1
  1676. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1677. assert.NoError(t, err)
  1678. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1679. testFileSize := int64(65535)
  1680. testFilePath := filepath.Join(homeBasePath, testFileName)
  1681. err = createTestFile(testFilePath, testFileSize)
  1682. assert.NoError(t, err)
  1683. testFileSize1 := int64(131072)
  1684. testFileName1 := "test_file1.dat"
  1685. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  1686. err = createTestFile(testFilePath1, testFileSize1)
  1687. assert.NoError(t, err)
  1688. testFileSize2 := int64(32768)
  1689. testFileName2 := "test_file2.dat"
  1690. testFilePath2 := filepath.Join(homeBasePath, testFileName2)
  1691. err = createTestFile(testFilePath2, testFileSize2)
  1692. assert.NoError(t, err)
  1693. // test quota files
  1694. client, err := getFTPClient(user, false, nil)
  1695. if assert.NoError(t, err) {
  1696. err = ftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client, 0)
  1697. assert.NoError(t, err)
  1698. err = ftpUploadFile(testFilePath, testFileName+".quota1", testFileSize, client, 0)
  1699. assert.Error(t, err)
  1700. err = client.Rename(testFileName+".quota", testFileName)
  1701. assert.NoError(t, err)
  1702. err = client.Quit()
  1703. assert.NoError(t, err)
  1704. }
  1705. // test quota size
  1706. user.QuotaSize = testFileSize - 1
  1707. user.QuotaFiles = 0
  1708. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1709. assert.NoError(t, err)
  1710. client, err = getFTPClient(user, true, nil)
  1711. if assert.NoError(t, err) {
  1712. err = ftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client, 0)
  1713. assert.Error(t, err)
  1714. err = client.Rename(testFileName, testFileName+".quota")
  1715. assert.NoError(t, err)
  1716. err = client.Quit()
  1717. assert.NoError(t, err)
  1718. }
  1719. // now test quota limits while uploading the current file, we have 1 bytes remaining
  1720. user.QuotaSize = testFileSize + 1
  1721. user.QuotaFiles = 0
  1722. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1723. assert.NoError(t, err)
  1724. client, err = getFTPClient(user, false, nil)
  1725. if assert.NoError(t, err) {
  1726. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  1727. assert.Error(t, err)
  1728. _, err = client.FileSize(testFileName1)
  1729. assert.Error(t, err)
  1730. err = client.Rename(testFileName+".quota", testFileName)
  1731. assert.NoError(t, err)
  1732. // overwriting an existing file will work if the resulting size is lesser or equal than the current one
  1733. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1734. assert.NoError(t, err)
  1735. err = ftpUploadFile(testFilePath2, testFileName, testFileSize2, client, 0)
  1736. assert.NoError(t, err)
  1737. err = ftpUploadFile(testFilePath1, testFileName, testFileSize1, client, 0)
  1738. assert.Error(t, err)
  1739. err = ftpUploadFile(testFilePath1, testFileName, testFileSize1, client, 10)
  1740. assert.Error(t, err)
  1741. err = ftpUploadFile(testFilePath2, testFileName, testFileSize2, client, 0)
  1742. assert.NoError(t, err)
  1743. err = client.Quit()
  1744. assert.NoError(t, err)
  1745. }
  1746. err = os.Remove(testFilePath)
  1747. assert.NoError(t, err)
  1748. err = os.Remove(testFilePath1)
  1749. assert.NoError(t, err)
  1750. err = os.Remove(testFilePath2)
  1751. assert.NoError(t, err)
  1752. if user.Username == defaultUsername {
  1753. err = os.RemoveAll(user.GetHomeDir())
  1754. assert.NoError(t, err)
  1755. user.QuotaFiles = 0
  1756. user.QuotaSize = 0
  1757. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1758. assert.NoError(t, err)
  1759. user.Password = defaultPassword
  1760. user.QuotaSize = 0
  1761. user.ID = 0
  1762. user.CreatedAt = 0
  1763. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  1764. assert.NoError(t, err, string(resp))
  1765. }
  1766. }
  1767. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1768. assert.NoError(t, err)
  1769. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1770. assert.NoError(t, err)
  1771. err = os.RemoveAll(localUser.GetHomeDir())
  1772. assert.NoError(t, err)
  1773. }
  1774. func TestUploadMaxSize(t *testing.T) {
  1775. testFileSize := int64(65535)
  1776. u := getTestUser()
  1777. u.Filters.MaxUploadFileSize = testFileSize + 1
  1778. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1779. assert.NoError(t, err)
  1780. u = getTestSFTPUser()
  1781. u.Filters.MaxUploadFileSize = testFileSize + 1
  1782. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1783. assert.NoError(t, err)
  1784. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1785. testFilePath := filepath.Join(homeBasePath, testFileName)
  1786. err = createTestFile(testFilePath, testFileSize)
  1787. assert.NoError(t, err)
  1788. testFileSize1 := int64(131072)
  1789. testFileName1 := "test_file1.dat"
  1790. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  1791. err = createTestFile(testFilePath1, testFileSize1)
  1792. assert.NoError(t, err)
  1793. client, err := getFTPClient(user, false, nil)
  1794. if assert.NoError(t, err) {
  1795. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  1796. assert.Error(t, err)
  1797. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1798. assert.NoError(t, err)
  1799. // now test overwrite an existing file with a size bigger than the allowed one
  1800. err = createTestFile(filepath.Join(user.GetHomeDir(), testFileName1), testFileSize1)
  1801. assert.NoError(t, err)
  1802. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  1803. assert.Error(t, err)
  1804. err = client.Quit()
  1805. assert.NoError(t, err)
  1806. }
  1807. err = os.Remove(testFilePath)
  1808. assert.NoError(t, err)
  1809. err = os.Remove(testFilePath1)
  1810. assert.NoError(t, err)
  1811. if user.Username == defaultUsername {
  1812. err = os.RemoveAll(user.GetHomeDir())
  1813. assert.NoError(t, err)
  1814. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1815. assert.NoError(t, err)
  1816. user.Password = defaultPassword
  1817. user.Filters.MaxUploadFileSize = 65536000
  1818. user.ID = 0
  1819. user.CreatedAt = 0
  1820. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  1821. assert.NoError(t, err, string(resp))
  1822. }
  1823. }
  1824. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1825. assert.NoError(t, err)
  1826. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1827. assert.NoError(t, err)
  1828. err = os.RemoveAll(localUser.GetHomeDir())
  1829. assert.NoError(t, err)
  1830. }
  1831. func TestLoginWithIPilters(t *testing.T) {
  1832. u := getTestUser()
  1833. u.Filters.DeniedIP = []string{"192.167.0.0/24", "172.18.0.0/16"}
  1834. u.Filters.AllowedIP = []string{"172.19.0.0/16"}
  1835. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1836. assert.NoError(t, err)
  1837. client, err := getFTPClient(user, true, nil)
  1838. if !assert.Error(t, err) {
  1839. err = client.Quit()
  1840. assert.NoError(t, err)
  1841. }
  1842. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1843. assert.NoError(t, err)
  1844. err = os.RemoveAll(user.GetHomeDir())
  1845. assert.NoError(t, err)
  1846. }
  1847. func TestLoginWithDatabaseCredentials(t *testing.T) {
  1848. u := getTestUser()
  1849. u.FsConfig.Provider = sdk.GCSFilesystemProvider
  1850. u.FsConfig.GCSConfig.Bucket = "test"
  1851. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret(`{ "type": "service_account" }`)
  1852. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1853. assert.NoError(t, err)
  1854. assert.Equal(t, sdkkms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus())
  1855. assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload())
  1856. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  1857. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey())
  1858. client, err := getFTPClient(user, false, nil)
  1859. if assert.NoError(t, err) {
  1860. err = client.Quit()
  1861. assert.NoError(t, err)
  1862. }
  1863. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1864. assert.NoError(t, err)
  1865. err = os.RemoveAll(user.GetHomeDir())
  1866. assert.NoError(t, err)
  1867. }
  1868. func TestLoginInvalidFs(t *testing.T) {
  1869. u := getTestUser()
  1870. u.FsConfig.Provider = sdk.GCSFilesystemProvider
  1871. u.FsConfig.GCSConfig.Bucket = "test"
  1872. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("invalid JSON for credentials")
  1873. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1874. assert.NoError(t, err)
  1875. client, err := getFTPClient(user, false, nil)
  1876. if !assert.Error(t, err) {
  1877. err = client.Quit()
  1878. assert.NoError(t, err)
  1879. }
  1880. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1881. assert.NoError(t, err)
  1882. err = os.RemoveAll(user.GetHomeDir())
  1883. assert.NoError(t, err)
  1884. }
  1885. func TestClientClose(t *testing.T) {
  1886. u := getTestUser()
  1887. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1888. assert.NoError(t, err)
  1889. client, err := getFTPClient(user, true, nil)
  1890. if assert.NoError(t, err) {
  1891. err = checkBasicFTP(client)
  1892. assert.NoError(t, err)
  1893. stats := common.Connections.GetStats()
  1894. if assert.Len(t, stats, 1) {
  1895. common.Connections.Close(stats[0].ConnectionID)
  1896. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  1897. 1*time.Second, 50*time.Millisecond)
  1898. }
  1899. }
  1900. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1901. assert.NoError(t, err)
  1902. err = os.RemoveAll(user.GetHomeDir())
  1903. assert.NoError(t, err)
  1904. }
  1905. func TestRename(t *testing.T) {
  1906. u := getTestUser()
  1907. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1908. assert.NoError(t, err)
  1909. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  1910. assert.NoError(t, err)
  1911. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1912. testDir := "adir"
  1913. testFilePath := filepath.Join(homeBasePath, testFileName)
  1914. testFileSize := int64(65535)
  1915. err = createTestFile(testFilePath, testFileSize)
  1916. assert.NoError(t, err)
  1917. client, err := getFTPClient(user, false, nil)
  1918. if assert.NoError(t, err) {
  1919. err = checkBasicFTP(client)
  1920. assert.NoError(t, err)
  1921. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1922. assert.NoError(t, err)
  1923. err = client.MakeDir(testDir)
  1924. assert.NoError(t, err)
  1925. err = client.Rename(testFileName, path.Join("missing", testFileName))
  1926. assert.Error(t, err)
  1927. err = client.Rename(testFileName, path.Join(testDir, testFileName))
  1928. assert.NoError(t, err)
  1929. size, err := client.FileSize(path.Join(testDir, testFileName))
  1930. assert.NoError(t, err)
  1931. assert.Equal(t, testFileSize, size)
  1932. if runtime.GOOS != osWindows {
  1933. otherDir := "dir"
  1934. err = client.MakeDir(otherDir)
  1935. assert.NoError(t, err)
  1936. err = client.MakeDir(path.Join(otherDir, testDir))
  1937. assert.NoError(t, err)
  1938. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 0001 %v", otherDir))
  1939. assert.NoError(t, err)
  1940. assert.Equal(t, ftp.StatusCommandOK, code)
  1941. assert.Equal(t, "SITE CHMOD command successful", response)
  1942. err = client.Rename(testDir, path.Join(otherDir, testDir))
  1943. assert.Error(t, err)
  1944. code, response, err = client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 755 %v", otherDir))
  1945. assert.NoError(t, err)
  1946. assert.Equal(t, ftp.StatusCommandOK, code)
  1947. assert.Equal(t, "SITE CHMOD command successful", response)
  1948. }
  1949. err = client.Quit()
  1950. assert.NoError(t, err)
  1951. }
  1952. user.Permissions[path.Join("/", testDir)] = []string{dataprovider.PermListItems}
  1953. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1954. assert.NoError(t, err)
  1955. client, err = getFTPClient(user, false, nil)
  1956. if assert.NoError(t, err) {
  1957. err = client.Rename(path.Join(testDir, testFileName), testFileName)
  1958. assert.Error(t, err)
  1959. err := client.Quit()
  1960. assert.NoError(t, err)
  1961. }
  1962. err = os.Remove(testFilePath)
  1963. assert.NoError(t, err)
  1964. if user.Username == defaultUsername {
  1965. err = os.RemoveAll(user.GetHomeDir())
  1966. assert.NoError(t, err)
  1967. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1968. assert.NoError(t, err)
  1969. user.Permissions = make(map[string][]string)
  1970. user.Permissions["/"] = allPerms
  1971. user.Password = defaultPassword
  1972. user.ID = 0
  1973. user.CreatedAt = 0
  1974. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  1975. assert.NoError(t, err, string(resp))
  1976. }
  1977. }
  1978. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1979. assert.NoError(t, err)
  1980. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1981. assert.NoError(t, err)
  1982. err = os.RemoveAll(localUser.GetHomeDir())
  1983. assert.NoError(t, err)
  1984. }
  1985. func TestSymlink(t *testing.T) {
  1986. u := getTestUser()
  1987. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1988. assert.NoError(t, err)
  1989. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  1990. assert.NoError(t, err)
  1991. testFilePath := filepath.Join(homeBasePath, testFileName)
  1992. testFileSize := int64(65535)
  1993. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1994. err = createTestFile(testFilePath, testFileSize)
  1995. assert.NoError(t, err)
  1996. client, err := getFTPClient(user, false, nil)
  1997. if assert.NoError(t, err) {
  1998. err = checkBasicFTP(client)
  1999. assert.NoError(t, err)
  2000. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2001. assert.NoError(t, err)
  2002. code, _, err := client.SendCustomCommand(fmt.Sprintf("SITE SYMLINK %v %v", testFileName, testFileName+".link"))
  2003. assert.NoError(t, err)
  2004. assert.Equal(t, ftp.StatusCommandOK, code)
  2005. if runtime.GOOS != osWindows {
  2006. testDir := "adir"
  2007. otherDir := "dir"
  2008. err = client.MakeDir(otherDir)
  2009. assert.NoError(t, err)
  2010. err = client.MakeDir(path.Join(otherDir, testDir))
  2011. assert.NoError(t, err)
  2012. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 0001 %v", otherDir))
  2013. assert.NoError(t, err)
  2014. assert.Equal(t, ftp.StatusCommandOK, code)
  2015. assert.Equal(t, "SITE CHMOD command successful", response)
  2016. code, _, err = client.SendCustomCommand(fmt.Sprintf("SITE SYMLINK %v %v", testDir, path.Join(otherDir, testDir)))
  2017. assert.NoError(t, err)
  2018. assert.Equal(t, ftp.StatusFileUnavailable, code)
  2019. code, response, err = client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 755 %v", otherDir))
  2020. assert.NoError(t, err)
  2021. assert.Equal(t, ftp.StatusCommandOK, code)
  2022. assert.Equal(t, "SITE CHMOD command successful", response)
  2023. }
  2024. err = client.Quit()
  2025. assert.NoError(t, err)
  2026. if user.Username == defaultUsername {
  2027. err = os.RemoveAll(user.GetHomeDir())
  2028. assert.NoError(t, err)
  2029. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2030. assert.NoError(t, err)
  2031. user.Password = defaultPassword
  2032. user.ID = 0
  2033. user.CreatedAt = 0
  2034. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2035. assert.NoError(t, err, string(resp))
  2036. }
  2037. }
  2038. err = os.Remove(testFilePath)
  2039. assert.NoError(t, err)
  2040. }
  2041. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2042. assert.NoError(t, err)
  2043. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2044. assert.NoError(t, err)
  2045. err = os.RemoveAll(localUser.GetHomeDir())
  2046. assert.NoError(t, err)
  2047. }
  2048. func TestStat(t *testing.T) {
  2049. u := getTestUser()
  2050. u.Permissions["/subdir"] = []string{dataprovider.PermUpload}
  2051. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2052. assert.NoError(t, err)
  2053. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2054. assert.NoError(t, err)
  2055. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2056. client, err := getFTPClient(user, false, nil)
  2057. if assert.NoError(t, err) {
  2058. subDir := "subdir"
  2059. testFilePath := filepath.Join(homeBasePath, testFileName)
  2060. testFileSize := int64(65535)
  2061. err = createTestFile(testFilePath, testFileSize)
  2062. assert.NoError(t, err)
  2063. err = client.MakeDir(subDir)
  2064. assert.NoError(t, err)
  2065. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2066. assert.NoError(t, err)
  2067. err = ftpUploadFile(testFilePath, path.Join("/", subDir, testFileName), testFileSize, client, 0)
  2068. assert.Error(t, err)
  2069. size, err := client.FileSize(testFileName)
  2070. assert.NoError(t, err)
  2071. assert.Equal(t, testFileSize, size)
  2072. _, err = client.FileSize(path.Join("/", subDir, testFileName))
  2073. assert.Error(t, err)
  2074. _, err = client.FileSize("missing file")
  2075. assert.Error(t, err)
  2076. err = client.Quit()
  2077. assert.NoError(t, err)
  2078. err = os.Remove(testFilePath)
  2079. assert.NoError(t, err)
  2080. if user.Username == defaultUsername {
  2081. err = os.RemoveAll(user.GetHomeDir())
  2082. assert.NoError(t, err)
  2083. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2084. assert.NoError(t, err)
  2085. user.Password = defaultPassword
  2086. user.ID = 0
  2087. user.CreatedAt = 0
  2088. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2089. assert.NoError(t, err, string(resp))
  2090. }
  2091. }
  2092. }
  2093. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2094. assert.NoError(t, err)
  2095. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2096. assert.NoError(t, err)
  2097. err = os.RemoveAll(localUser.GetHomeDir())
  2098. assert.NoError(t, err)
  2099. }
  2100. func TestUploadOverwriteVfolder(t *testing.T) {
  2101. u := getTestUser()
  2102. vdir := "/vdir"
  2103. mappedPath := filepath.Join(os.TempDir(), "vdir")
  2104. folderName := filepath.Base(mappedPath)
  2105. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  2106. BaseVirtualFolder: vfs.BaseVirtualFolder{
  2107. Name: folderName,
  2108. MappedPath: mappedPath,
  2109. },
  2110. VirtualPath: vdir,
  2111. QuotaSize: -1,
  2112. QuotaFiles: -1,
  2113. })
  2114. err := os.MkdirAll(mappedPath, os.ModePerm)
  2115. assert.NoError(t, err)
  2116. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2117. assert.NoError(t, err)
  2118. client, err := getFTPClient(user, false, nil)
  2119. if assert.NoError(t, err) {
  2120. testFilePath := filepath.Join(homeBasePath, testFileName)
  2121. testFileSize := int64(65535)
  2122. err = createTestFile(testFilePath, testFileSize)
  2123. assert.NoError(t, err)
  2124. err = ftpUploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client, 0)
  2125. assert.NoError(t, err)
  2126. folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
  2127. assert.NoError(t, err)
  2128. assert.Equal(t, testFileSize, folder.UsedQuotaSize)
  2129. assert.Equal(t, 1, folder.UsedQuotaFiles)
  2130. err = ftpUploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client, 0)
  2131. assert.NoError(t, err)
  2132. folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK)
  2133. assert.NoError(t, err)
  2134. assert.Equal(t, testFileSize, folder.UsedQuotaSize)
  2135. assert.Equal(t, 1, folder.UsedQuotaFiles)
  2136. err = client.Quit()
  2137. assert.NoError(t, err)
  2138. err = os.Remove(testFilePath)
  2139. assert.NoError(t, err)
  2140. }
  2141. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2142. assert.NoError(t, err)
  2143. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  2144. assert.NoError(t, err)
  2145. err = os.RemoveAll(user.GetHomeDir())
  2146. assert.NoError(t, err)
  2147. err = os.RemoveAll(mappedPath)
  2148. assert.NoError(t, err)
  2149. }
  2150. func TestTransferQuotaLimits(t *testing.T) {
  2151. u := getTestUser()
  2152. u.DownloadDataTransfer = 1
  2153. u.UploadDataTransfer = 1
  2154. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2155. assert.NoError(t, err)
  2156. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  2157. testFilePath := filepath.Join(homeBasePath, testFileName)
  2158. testFileSize := int64(524288)
  2159. err = createTestFile(testFilePath, testFileSize)
  2160. assert.NoError(t, err)
  2161. client, err := getFTPClient(user, false, nil)
  2162. if assert.NoError(t, err) {
  2163. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2164. assert.NoError(t, err)
  2165. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2166. assert.NoError(t, err)
  2167. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2168. if assert.Error(t, err) {
  2169. assert.Contains(t, err.Error(), ftpserver.ErrStorageExceeded.Error())
  2170. }
  2171. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2172. assert.NoError(t, err)
  2173. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2174. assert.NoError(t, err)
  2175. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2176. if assert.Error(t, err) {
  2177. assert.Contains(t, err.Error(), common.ErrReadQuotaExceeded.Error())
  2178. }
  2179. err = client.Quit()
  2180. assert.NoError(t, err)
  2181. }
  2182. testFileSize = int64(600000)
  2183. err = createTestFile(testFilePath, testFileSize)
  2184. assert.NoError(t, err)
  2185. user.DownloadDataTransfer = 2
  2186. user.UploadDataTransfer = 2
  2187. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2188. assert.NoError(t, err)
  2189. client, err = getFTPClient(user, false, nil)
  2190. if assert.NoError(t, err) {
  2191. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2192. assert.NoError(t, err)
  2193. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2194. assert.NoError(t, err)
  2195. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  2196. assert.Error(t, err)
  2197. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2198. assert.Error(t, err)
  2199. err = client.Quit()
  2200. assert.NoError(t, err)
  2201. }
  2202. err = os.Remove(localDownloadPath)
  2203. assert.NoError(t, err)
  2204. err = os.Remove(testFilePath)
  2205. assert.NoError(t, err)
  2206. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2207. assert.NoError(t, err)
  2208. err = os.RemoveAll(user.GetHomeDir())
  2209. assert.NoError(t, err)
  2210. }
  2211. func TestAllocateAvailable(t *testing.T) {
  2212. u := getTestUser()
  2213. mappedPath := filepath.Join(os.TempDir(), "vdir")
  2214. folderName := filepath.Base(mappedPath)
  2215. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  2216. BaseVirtualFolder: vfs.BaseVirtualFolder{
  2217. Name: folderName,
  2218. MappedPath: mappedPath,
  2219. },
  2220. VirtualPath: "/vdir",
  2221. QuotaSize: 110,
  2222. })
  2223. err := os.MkdirAll(mappedPath, os.ModePerm)
  2224. assert.NoError(t, err)
  2225. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2226. assert.NoError(t, err)
  2227. client, err := getFTPClient(user, false, nil)
  2228. if assert.NoError(t, err) {
  2229. code, response, err := client.SendCustomCommand("allo 2000000")
  2230. assert.NoError(t, err)
  2231. assert.Equal(t, ftp.StatusCommandOK, code)
  2232. assert.Equal(t, "Done !", response)
  2233. code, response, err = client.SendCustomCommand("AVBL /vdir")
  2234. assert.NoError(t, err)
  2235. assert.Equal(t, ftp.StatusFile, code)
  2236. assert.Equal(t, "110", response)
  2237. code, _, err = client.SendCustomCommand("AVBL")
  2238. assert.NoError(t, err)
  2239. assert.Equal(t, ftp.StatusFile, code)
  2240. err = client.Quit()
  2241. assert.NoError(t, err)
  2242. }
  2243. user.QuotaSize = 100
  2244. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2245. assert.NoError(t, err)
  2246. client, err = getFTPClient(user, false, nil)
  2247. if assert.NoError(t, err) {
  2248. testFilePath := filepath.Join(homeBasePath, testFileName)
  2249. testFileSize := user.QuotaSize - 1
  2250. err = createTestFile(testFilePath, testFileSize)
  2251. assert.NoError(t, err)
  2252. code, response, err := client.SendCustomCommand("allo 1000")
  2253. assert.NoError(t, err)
  2254. assert.Equal(t, ftp.StatusCommandOK, code)
  2255. assert.Equal(t, "Done !", response)
  2256. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2257. assert.NoError(t, err)
  2258. code, response, err = client.SendCustomCommand("AVBL")
  2259. assert.NoError(t, err)
  2260. assert.Equal(t, ftp.StatusFile, code)
  2261. assert.Equal(t, "1", response)
  2262. err = client.Quit()
  2263. assert.NoError(t, err)
  2264. err = os.Remove(testFilePath)
  2265. assert.NoError(t, err)
  2266. }
  2267. user.TotalDataTransfer = 1
  2268. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2269. assert.NoError(t, err)
  2270. client, err = getFTPClient(user, false, nil)
  2271. if assert.NoError(t, err) {
  2272. code, response, err := client.SendCustomCommand("AVBL")
  2273. assert.NoError(t, err)
  2274. assert.Equal(t, ftp.StatusFile, code)
  2275. assert.Equal(t, "1", response)
  2276. err = client.Quit()
  2277. assert.NoError(t, err)
  2278. }
  2279. user.TotalDataTransfer = 0
  2280. user.UploadDataTransfer = 5
  2281. user.QuotaSize = 6 * 1024 * 1024
  2282. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2283. assert.NoError(t, err)
  2284. client, err = getFTPClient(user, false, nil)
  2285. if assert.NoError(t, err) {
  2286. code, response, err := client.SendCustomCommand("AVBL")
  2287. assert.NoError(t, err)
  2288. assert.Equal(t, ftp.StatusFile, code)
  2289. assert.Equal(t, "5242880", response)
  2290. err = client.Quit()
  2291. assert.NoError(t, err)
  2292. }
  2293. user.TotalDataTransfer = 0
  2294. user.UploadDataTransfer = 5
  2295. user.QuotaSize = 0
  2296. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2297. assert.NoError(t, err)
  2298. client, err = getFTPClient(user, false, nil)
  2299. if assert.NoError(t, err) {
  2300. code, response, err := client.SendCustomCommand("AVBL")
  2301. assert.NoError(t, err)
  2302. assert.Equal(t, ftp.StatusFile, code)
  2303. assert.Equal(t, "5242880", response)
  2304. err = client.Quit()
  2305. assert.NoError(t, err)
  2306. }
  2307. user.Filters.MaxUploadFileSize = 100
  2308. user.QuotaSize = 0
  2309. user.TotalDataTransfer = 0
  2310. user.UploadDataTransfer = 0
  2311. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2312. assert.NoError(t, err)
  2313. client, err = getFTPClient(user, false, nil)
  2314. if assert.NoError(t, err) {
  2315. code, response, err := client.SendCustomCommand("allo 10000")
  2316. assert.NoError(t, err)
  2317. assert.Equal(t, ftp.StatusCommandOK, code)
  2318. assert.Equal(t, "Done !", response)
  2319. code, response, err = client.SendCustomCommand("AVBL")
  2320. assert.NoError(t, err)
  2321. assert.Equal(t, ftp.StatusFile, code)
  2322. assert.Equal(t, "100", response)
  2323. err = client.Quit()
  2324. assert.NoError(t, err)
  2325. }
  2326. user.QuotaSize = 50
  2327. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2328. assert.NoError(t, err)
  2329. client, err = getFTPClient(user, false, nil)
  2330. if assert.NoError(t, err) {
  2331. code, response, err := client.SendCustomCommand("AVBL")
  2332. assert.NoError(t, err)
  2333. assert.Equal(t, ftp.StatusFile, code)
  2334. assert.Equal(t, "0", response)
  2335. }
  2336. user.QuotaSize = 1000
  2337. user.Filters.MaxUploadFileSize = 1
  2338. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2339. assert.NoError(t, err)
  2340. client, err = getFTPClient(user, false, nil)
  2341. if assert.NoError(t, err) {
  2342. code, response, err := client.SendCustomCommand("AVBL")
  2343. assert.NoError(t, err)
  2344. assert.Equal(t, ftp.StatusFile, code)
  2345. assert.Equal(t, "1", response)
  2346. }
  2347. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2348. assert.NoError(t, err)
  2349. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  2350. assert.NoError(t, err)
  2351. err = os.RemoveAll(user.GetHomeDir())
  2352. assert.NoError(t, err)
  2353. err = os.RemoveAll(mappedPath)
  2354. assert.NoError(t, err)
  2355. }
  2356. func TestAvailableSFTPFs(t *testing.T) {
  2357. u := getTestUser()
  2358. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2359. assert.NoError(t, err)
  2360. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2361. assert.NoError(t, err)
  2362. client, err := getFTPClient(sftpUser, false, nil)
  2363. if assert.NoError(t, err) {
  2364. code, response, err := client.SendCustomCommand("AVBL /")
  2365. assert.NoError(t, err)
  2366. assert.Equal(t, ftp.StatusFile, code)
  2367. avblSize, err := strconv.ParseInt(response, 10, 64)
  2368. assert.NoError(t, err)
  2369. assert.Greater(t, avblSize, int64(0))
  2370. err = client.Quit()
  2371. assert.NoError(t, err)
  2372. }
  2373. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2374. assert.NoError(t, err)
  2375. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2376. assert.NoError(t, err)
  2377. err = os.RemoveAll(localUser.GetHomeDir())
  2378. assert.NoError(t, err)
  2379. }
  2380. func TestChtimes(t *testing.T) {
  2381. u := getTestUser()
  2382. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2383. assert.NoError(t, err)
  2384. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2385. assert.NoError(t, err)
  2386. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2387. client, err := getFTPClient(user, false, nil)
  2388. if assert.NoError(t, err) {
  2389. testFilePath := filepath.Join(homeBasePath, testFileName)
  2390. testFileSize := int64(65535)
  2391. err = createTestFile(testFilePath, testFileSize)
  2392. assert.NoError(t, err)
  2393. err = checkBasicFTP(client)
  2394. assert.NoError(t, err)
  2395. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2396. assert.NoError(t, err)
  2397. mtime := time.Now().Format("20060102150405")
  2398. code, response, err := client.SendCustomCommand(fmt.Sprintf("MFMT %v %v", mtime, testFileName))
  2399. assert.NoError(t, err)
  2400. assert.Equal(t, ftp.StatusFile, code)
  2401. assert.Equal(t, fmt.Sprintf("Modify=%v; %v", mtime, testFileName), response)
  2402. err = client.Quit()
  2403. assert.NoError(t, err)
  2404. err = os.Remove(testFilePath)
  2405. assert.NoError(t, err)
  2406. if user.Username == defaultUsername {
  2407. err = os.RemoveAll(user.GetHomeDir())
  2408. assert.NoError(t, err)
  2409. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2410. assert.NoError(t, err)
  2411. user.Password = defaultPassword
  2412. user.ID = 0
  2413. user.CreatedAt = 0
  2414. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2415. assert.NoError(t, err, string(resp))
  2416. }
  2417. }
  2418. }
  2419. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2420. assert.NoError(t, err)
  2421. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2422. assert.NoError(t, err)
  2423. err = os.RemoveAll(localUser.GetHomeDir())
  2424. assert.NoError(t, err)
  2425. }
  2426. func TestChown(t *testing.T) {
  2427. if runtime.GOOS == osWindows {
  2428. t.Skip("chown is not supported on Windows")
  2429. }
  2430. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  2431. assert.NoError(t, err)
  2432. client, err := getFTPClient(user, true, nil)
  2433. if assert.NoError(t, err) {
  2434. testFilePath := filepath.Join(homeBasePath, testFileName)
  2435. testFileSize := int64(131072)
  2436. err = createTestFile(testFilePath, testFileSize)
  2437. assert.NoError(t, err)
  2438. err = checkBasicFTP(client)
  2439. assert.NoError(t, err)
  2440. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2441. assert.NoError(t, err)
  2442. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHOWN 1000:1000 %v", testFileName))
  2443. assert.NoError(t, err)
  2444. assert.Equal(t, ftp.StatusFileUnavailable, code)
  2445. assert.Equal(t, "Couldn't chown: operation unsupported", response)
  2446. err = client.Quit()
  2447. assert.NoError(t, err)
  2448. err = os.Remove(testFilePath)
  2449. assert.NoError(t, err)
  2450. }
  2451. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2452. assert.NoError(t, err)
  2453. err = os.RemoveAll(user.GetHomeDir())
  2454. assert.NoError(t, err)
  2455. }
  2456. func TestChmod(t *testing.T) {
  2457. if runtime.GOOS == osWindows {
  2458. t.Skip("chmod is partially supported on Windows")
  2459. }
  2460. u := getTestUser()
  2461. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2462. assert.NoError(t, err)
  2463. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2464. assert.NoError(t, err)
  2465. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2466. client, err := getFTPClient(user, true, nil)
  2467. if assert.NoError(t, err) {
  2468. testFilePath := filepath.Join(homeBasePath, testFileName)
  2469. testFileSize := int64(131072)
  2470. err = createTestFile(testFilePath, testFileSize)
  2471. assert.NoError(t, err)
  2472. err = checkBasicFTP(client)
  2473. assert.NoError(t, err)
  2474. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2475. assert.NoError(t, err)
  2476. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 600 %v", testFileName))
  2477. assert.NoError(t, err)
  2478. assert.Equal(t, ftp.StatusCommandOK, code)
  2479. assert.Equal(t, "SITE CHMOD command successful", response)
  2480. fi, err := os.Stat(filepath.Join(user.HomeDir, testFileName))
  2481. if assert.NoError(t, err) {
  2482. assert.Equal(t, os.FileMode(0600), fi.Mode().Perm())
  2483. }
  2484. err = client.Quit()
  2485. assert.NoError(t, err)
  2486. err = os.Remove(testFilePath)
  2487. assert.NoError(t, err)
  2488. if user.Username == defaultUsername {
  2489. err = os.RemoveAll(user.GetHomeDir())
  2490. assert.NoError(t, err)
  2491. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2492. assert.NoError(t, err)
  2493. user.Password = defaultPassword
  2494. user.ID = 0
  2495. user.CreatedAt = 0
  2496. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2497. assert.NoError(t, err, string(resp))
  2498. }
  2499. }
  2500. }
  2501. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2502. assert.NoError(t, err)
  2503. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2504. assert.NoError(t, err)
  2505. err = os.RemoveAll(localUser.GetHomeDir())
  2506. assert.NoError(t, err)
  2507. }
  2508. func TestCombineDisabled(t *testing.T) {
  2509. u := getTestUser()
  2510. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2511. assert.NoError(t, err)
  2512. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2513. assert.NoError(t, err)
  2514. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2515. client, err := getFTPClient(user, true, nil)
  2516. if assert.NoError(t, err) {
  2517. err = checkBasicFTP(client)
  2518. assert.NoError(t, err)
  2519. code, response, err := client.SendCustomCommand("COMB file file.1 file.2")
  2520. assert.NoError(t, err)
  2521. assert.Equal(t, ftp.StatusNotImplemented, code)
  2522. assert.Equal(t, "COMB support is disabled", response)
  2523. err = client.Quit()
  2524. assert.NoError(t, err)
  2525. }
  2526. }
  2527. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2528. assert.NoError(t, err)
  2529. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2530. assert.NoError(t, err)
  2531. err = os.RemoveAll(localUser.GetHomeDir())
  2532. assert.NoError(t, err)
  2533. }
  2534. func TestActiveModeDisabled(t *testing.T) {
  2535. u := getTestUser()
  2536. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2537. assert.NoError(t, err)
  2538. client, err := getFTPClientImplicitTLS(user)
  2539. if assert.NoError(t, err) {
  2540. err = checkBasicFTP(client)
  2541. assert.NoError(t, err)
  2542. code, response, err := client.SendCustomCommand("PORT 10,2,0,2,4,31")
  2543. assert.NoError(t, err)
  2544. assert.Equal(t, ftp.StatusNotAvailable, code)
  2545. assert.Equal(t, "PORT command is disabled", response)
  2546. code, response, err = client.SendCustomCommand("EPRT |1|132.235.1.2|6275|")
  2547. assert.NoError(t, err)
  2548. assert.Equal(t, ftp.StatusNotAvailable, code)
  2549. assert.Equal(t, "EPRT command is disabled", response)
  2550. err = client.Quit()
  2551. assert.NoError(t, err)
  2552. }
  2553. client, err = getFTPClient(user, false, nil)
  2554. if assert.NoError(t, err) {
  2555. code, response, err := client.SendCustomCommand("PORT 10,2,0,2,4,31")
  2556. assert.NoError(t, err)
  2557. assert.Equal(t, ftp.StatusBadArguments, code)
  2558. assert.Equal(t, "Your request does not meet the configured security requirements", response)
  2559. code, response, err = client.SendCustomCommand("EPRT |1|132.235.1.2|6275|")
  2560. assert.NoError(t, err)
  2561. assert.Equal(t, ftp.StatusBadArguments, code)
  2562. assert.Equal(t, "Your request does not meet the configured security requirements", response)
  2563. err = client.Quit()
  2564. assert.NoError(t, err)
  2565. }
  2566. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2567. assert.NoError(t, err)
  2568. err = os.RemoveAll(user.GetHomeDir())
  2569. assert.NoError(t, err)
  2570. }
  2571. func TestSITEDisabled(t *testing.T) {
  2572. u := getTestUser()
  2573. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2574. assert.NoError(t, err)
  2575. client, err := getFTPClientImplicitTLS(user)
  2576. if assert.NoError(t, err) {
  2577. err = checkBasicFTP(client)
  2578. assert.NoError(t, err)
  2579. code, response, err := client.SendCustomCommand("SITE CHMOD 600 afile.txt")
  2580. assert.NoError(t, err)
  2581. assert.Equal(t, ftp.StatusBadCommand, code)
  2582. assert.Equal(t, "SITE support is disabled", response)
  2583. err = client.Quit()
  2584. assert.NoError(t, err)
  2585. }
  2586. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2587. assert.NoError(t, err)
  2588. err = os.RemoveAll(user.GetHomeDir())
  2589. assert.NoError(t, err)
  2590. }
  2591. func TestHASH(t *testing.T) {
  2592. u := getTestUser()
  2593. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2594. assert.NoError(t, err)
  2595. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2596. assert.NoError(t, err)
  2597. u = getTestUserWithCryptFs()
  2598. u.Username += "_crypt"
  2599. cryptUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2600. assert.NoError(t, err)
  2601. for _, user := range []dataprovider.User{localUser, sftpUser, cryptUser} {
  2602. client, err := getFTPClientImplicitTLS(user)
  2603. if assert.NoError(t, err) {
  2604. testFilePath := filepath.Join(homeBasePath, testFileName)
  2605. testFileSize := int64(131072)
  2606. err = createTestFile(testFilePath, testFileSize)
  2607. assert.NoError(t, err)
  2608. err = checkBasicFTP(client)
  2609. assert.NoError(t, err)
  2610. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  2611. assert.NoError(t, err)
  2612. h := sha256.New()
  2613. f, err := os.Open(testFilePath)
  2614. assert.NoError(t, err)
  2615. _, err = io.Copy(h, f)
  2616. assert.NoError(t, err)
  2617. hash := hex.EncodeToString(h.Sum(nil))
  2618. err = f.Close()
  2619. assert.NoError(t, err)
  2620. code, response, err := client.SendCustomCommand(fmt.Sprintf("XSHA256 %v", testFileName))
  2621. assert.NoError(t, err)
  2622. assert.Equal(t, ftp.StatusRequestedFileActionOK, code)
  2623. assert.Contains(t, response, hash)
  2624. code, response, err = client.SendCustomCommand(fmt.Sprintf("HASH %v", testFileName))
  2625. assert.NoError(t, err)
  2626. assert.Equal(t, ftp.StatusFile, code)
  2627. assert.Contains(t, response, hash)
  2628. err = client.Quit()
  2629. assert.NoError(t, err)
  2630. err = os.Remove(testFilePath)
  2631. assert.NoError(t, err)
  2632. if user.Username == defaultUsername {
  2633. err = os.RemoveAll(user.GetHomeDir())
  2634. assert.NoError(t, err)
  2635. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2636. assert.NoError(t, err)
  2637. user.Password = defaultPassword
  2638. user.ID = 0
  2639. user.CreatedAt = 0
  2640. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2641. assert.NoError(t, err, string(resp))
  2642. }
  2643. }
  2644. }
  2645. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2646. assert.NoError(t, err)
  2647. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2648. assert.NoError(t, err)
  2649. err = os.RemoveAll(localUser.GetHomeDir())
  2650. assert.NoError(t, err)
  2651. _, err = httpdtest.RemoveUser(cryptUser, http.StatusOK)
  2652. assert.NoError(t, err)
  2653. err = os.RemoveAll(cryptUser.GetHomeDir())
  2654. assert.NoError(t, err)
  2655. }
  2656. func TestCombine(t *testing.T) {
  2657. u := getTestUser()
  2658. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2659. assert.NoError(t, err)
  2660. sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
  2661. assert.NoError(t, err)
  2662. for _, user := range []dataprovider.User{localUser, sftpUser} {
  2663. client, err := getFTPClientImplicitTLS(user)
  2664. if assert.NoError(t, err) {
  2665. testFilePath := filepath.Join(homeBasePath, testFileName)
  2666. testFileSize := int64(131072)
  2667. err = createTestFile(testFilePath, testFileSize)
  2668. assert.NoError(t, err)
  2669. err = checkBasicFTP(client)
  2670. assert.NoError(t, err)
  2671. err = ftpUploadFile(testFilePath, testFileName+".1", testFileSize, client, 0)
  2672. assert.NoError(t, err)
  2673. err = ftpUploadFile(testFilePath, testFileName+".2", testFileSize, client, 0)
  2674. assert.NoError(t, err)
  2675. code, response, err := client.SendCustomCommand(fmt.Sprintf("COMB %v %v %v", testFileName, testFileName+".1", testFileName+".2"))
  2676. assert.NoError(t, err)
  2677. if user.Username == defaultUsername {
  2678. assert.Equal(t, ftp.StatusRequestedFileActionOK, code)
  2679. assert.Equal(t, "COMB succeeded!", response)
  2680. } else {
  2681. assert.Equal(t, ftp.StatusFileUnavailable, code)
  2682. assert.Contains(t, response, "COMB is not supported for this filesystem")
  2683. }
  2684. err = client.Quit()
  2685. assert.NoError(t, err)
  2686. err = os.Remove(testFilePath)
  2687. assert.NoError(t, err)
  2688. if user.Username == defaultUsername {
  2689. err = os.RemoveAll(user.GetHomeDir())
  2690. assert.NoError(t, err)
  2691. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2692. assert.NoError(t, err)
  2693. user.Password = defaultPassword
  2694. user.ID = 0
  2695. user.CreatedAt = 0
  2696. _, resp, err := httpdtest.AddUser(user, http.StatusCreated)
  2697. assert.NoError(t, err, string(resp))
  2698. }
  2699. }
  2700. }
  2701. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  2702. assert.NoError(t, err)
  2703. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  2704. assert.NoError(t, err)
  2705. err = os.RemoveAll(localUser.GetHomeDir())
  2706. assert.NoError(t, err)
  2707. }
  2708. func TestClientCertificateAuthRevokedCert(t *testing.T) {
  2709. u := getTestUser()
  2710. u.Username = tlsClient2Username
  2711. u.Filters.TLSUsername = sdk.TLSUsernameCN
  2712. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2713. assert.NoError(t, err)
  2714. tlsConfig := &tls.Config{
  2715. ServerName: "localhost",
  2716. InsecureSkipVerify: true, // use this for tests only
  2717. MinVersion: tls.VersionTLS12,
  2718. }
  2719. tlsCert, err := tls.X509KeyPair([]byte(client2Crt), []byte(client2Key))
  2720. assert.NoError(t, err)
  2721. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  2722. _, err = getFTPClient(user, true, tlsConfig)
  2723. if assert.Error(t, err) {
  2724. assert.Contains(t, err.Error(), "bad certificate")
  2725. }
  2726. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2727. assert.NoError(t, err)
  2728. err = os.RemoveAll(user.GetHomeDir())
  2729. assert.NoError(t, err)
  2730. }
  2731. func TestClientCertificateAuth(t *testing.T) {
  2732. u := getTestUser()
  2733. u.Username = tlsClient1Username
  2734. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  2735. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2736. assert.NoError(t, err)
  2737. tlsConfig := &tls.Config{
  2738. ServerName: "localhost",
  2739. InsecureSkipVerify: true, // use this for tests only
  2740. MinVersion: tls.VersionTLS12,
  2741. }
  2742. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  2743. assert.NoError(t, err)
  2744. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  2745. // TLS username is not enabled, mutual TLS should fail
  2746. _, err = getFTPClient(user, true, tlsConfig)
  2747. if assert.Error(t, err) {
  2748. assert.Contains(t, err.Error(), "login method password is not allowed")
  2749. }
  2750. user.Filters.TLSUsername = sdk.TLSUsernameCN
  2751. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2752. assert.NoError(t, err)
  2753. client, err := getFTPClient(user, true, tlsConfig)
  2754. if assert.NoError(t, err) {
  2755. err = checkBasicFTP(client)
  2756. assert.NoError(t, err)
  2757. err = client.Quit()
  2758. assert.NoError(t, err)
  2759. }
  2760. // now use a valid certificate with a CN different from username
  2761. u = getTestUser()
  2762. u.Username = tlsClient2Username
  2763. u.Filters.TLSUsername = sdk.TLSUsernameCN
  2764. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  2765. user2, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2766. assert.NoError(t, err)
  2767. _, err = getFTPClient(user2, true, tlsConfig)
  2768. if assert.Error(t, err) {
  2769. assert.Contains(t, err.Error(), "does not match username")
  2770. }
  2771. // now disable certificate authentication
  2772. user.Filters.DeniedLoginMethods = append(user.Filters.DeniedLoginMethods, dataprovider.LoginMethodTLSCertificate,
  2773. dataprovider.LoginMethodTLSCertificateAndPwd)
  2774. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2775. assert.NoError(t, err)
  2776. _, err = getFTPClient(user, true, tlsConfig)
  2777. if assert.Error(t, err) {
  2778. assert.Contains(t, err.Error(), "login method TLSCertificate+password is not allowed")
  2779. }
  2780. // disable FTP protocol
  2781. user.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  2782. user.Filters.DeniedProtocols = append(user.Filters.DeniedProtocols, common.ProtocolFTP)
  2783. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  2784. assert.NoError(t, err)
  2785. _, err = getFTPClient(user, true, tlsConfig)
  2786. if assert.Error(t, err) {
  2787. assert.Contains(t, err.Error(), "protocol FTP is not allowed")
  2788. }
  2789. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2790. assert.NoError(t, err)
  2791. err = os.RemoveAll(user.GetHomeDir())
  2792. assert.NoError(t, err)
  2793. _, err = httpdtest.RemoveUser(user2, http.StatusOK)
  2794. assert.NoError(t, err)
  2795. err = os.RemoveAll(user2.GetHomeDir())
  2796. assert.NoError(t, err)
  2797. _, err = getFTPClient(user, true, tlsConfig)
  2798. assert.Error(t, err)
  2799. }
  2800. func TestClientCertificateAndPwdAuth(t *testing.T) {
  2801. u := getTestUser()
  2802. u.Username = tlsClient1Username
  2803. u.Filters.TLSUsername = sdk.TLSUsernameCN
  2804. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword, dataprovider.LoginMethodTLSCertificate}
  2805. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2806. assert.NoError(t, err)
  2807. tlsConfig := &tls.Config{
  2808. ServerName: "localhost",
  2809. InsecureSkipVerify: true, // use this for tests only
  2810. MinVersion: tls.VersionTLS12,
  2811. }
  2812. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  2813. assert.NoError(t, err)
  2814. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  2815. client, err := getFTPClient(user, true, tlsConfig)
  2816. if assert.NoError(t, err) {
  2817. err = checkBasicFTP(client)
  2818. assert.NoError(t, err)
  2819. err = client.Quit()
  2820. assert.NoError(t, err)
  2821. }
  2822. _, err = getFTPClient(user, true, nil)
  2823. if assert.Error(t, err) {
  2824. assert.Contains(t, err.Error(), "login method password is not allowed")
  2825. }
  2826. user.Password = defaultPassword + "1"
  2827. _, err = getFTPClient(user, true, tlsConfig)
  2828. if assert.Error(t, err) {
  2829. assert.Contains(t, err.Error(), "invalid credentials")
  2830. }
  2831. tlsCert, err = tls.X509KeyPair([]byte(client2Crt), []byte(client2Key))
  2832. assert.NoError(t, err)
  2833. tlsConfig.Certificates = []tls.Certificate{tlsCert}
  2834. _, err = getFTPClient(user, true, tlsConfig)
  2835. if assert.Error(t, err) {
  2836. assert.Contains(t, err.Error(), "bad certificate")
  2837. }
  2838. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2839. assert.NoError(t, err)
  2840. err = os.RemoveAll(user.GetHomeDir())
  2841. assert.NoError(t, err)
  2842. }
  2843. func TestExternalAuthWithClientCert(t *testing.T) {
  2844. if runtime.GOOS == osWindows {
  2845. t.Skip("this test is not available on Windows")
  2846. }
  2847. u := getTestUser()
  2848. u.Username = tlsClient1Username
  2849. u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, dataprovider.LoginMethodPassword)
  2850. u.Filters.TLSUsername = sdk.TLSUsernameCN
  2851. err := dataprovider.Close()
  2852. assert.NoError(t, err)
  2853. err = config.LoadConfig(configDir, "")
  2854. assert.NoError(t, err)
  2855. providerConf := config.GetProviderConf()
  2856. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u), os.ModePerm)
  2857. assert.NoError(t, err)
  2858. providerConf.ExternalAuthHook = extAuthPath
  2859. providerConf.ExternalAuthScope = 8
  2860. err = dataprovider.Initialize(providerConf, configDir, true)
  2861. assert.NoError(t, err)
  2862. // external auth not called, auth scope is 8
  2863. _, err = getFTPClient(u, true, nil)
  2864. assert.Error(t, err)
  2865. _, _, err = httpdtest.GetUserByUsername(u.Username, http.StatusNotFound)
  2866. assert.NoError(t, err)
  2867. tlsConfig := &tls.Config{
  2868. ServerName: "localhost",
  2869. InsecureSkipVerify: true, // use this for tests only
  2870. MinVersion: tls.VersionTLS12,
  2871. }
  2872. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  2873. assert.NoError(t, err)
  2874. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  2875. client, err := getFTPClient(u, true, tlsConfig)
  2876. if assert.NoError(t, err) {
  2877. err = checkBasicFTP(client)
  2878. assert.NoError(t, err)
  2879. err := client.Quit()
  2880. assert.NoError(t, err)
  2881. }
  2882. user, _, err := httpdtest.GetUserByUsername(u.Username, http.StatusOK)
  2883. assert.NoError(t, err)
  2884. assert.Equal(t, u.Username, user.Username)
  2885. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2886. assert.NoError(t, err)
  2887. err = os.RemoveAll(user.GetHomeDir())
  2888. assert.NoError(t, err)
  2889. u.Username = tlsClient2Username
  2890. _, err = getFTPClient(u, true, tlsConfig)
  2891. if assert.Error(t, err) {
  2892. assert.Contains(t, err.Error(), "invalid credentials")
  2893. }
  2894. err = dataprovider.Close()
  2895. assert.NoError(t, err)
  2896. err = config.LoadConfig(configDir, "")
  2897. assert.NoError(t, err)
  2898. providerConf = config.GetProviderConf()
  2899. err = dataprovider.Initialize(providerConf, configDir, true)
  2900. assert.NoError(t, err)
  2901. err = os.Remove(extAuthPath)
  2902. assert.NoError(t, err)
  2903. }
  2904. func TestPreLoginHookWithClientCert(t *testing.T) {
  2905. if runtime.GOOS == osWindows {
  2906. t.Skip("this test is not available on Windows")
  2907. }
  2908. u := getTestUser()
  2909. u.Username = tlsClient1Username
  2910. u.Filters.DeniedLoginMethods = append(u.Filters.DeniedLoginMethods, dataprovider.LoginMethodPassword)
  2911. u.Filters.TLSUsername = sdk.TLSUsernameCN
  2912. err := dataprovider.Close()
  2913. assert.NoError(t, err)
  2914. err = config.LoadConfig(configDir, "")
  2915. assert.NoError(t, err)
  2916. providerConf := config.GetProviderConf()
  2917. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  2918. assert.NoError(t, err)
  2919. providerConf.PreLoginHook = preLoginPath
  2920. err = dataprovider.Initialize(providerConf, configDir, true)
  2921. assert.NoError(t, err)
  2922. _, _, err = httpdtest.GetUserByUsername(tlsClient1Username, http.StatusNotFound)
  2923. assert.NoError(t, err)
  2924. tlsConfig := &tls.Config{
  2925. ServerName: "localhost",
  2926. InsecureSkipVerify: true, // use this for tests only
  2927. MinVersion: tls.VersionTLS12,
  2928. }
  2929. tlsCert, err := tls.X509KeyPair([]byte(client1Crt), []byte(client1Key))
  2930. assert.NoError(t, err)
  2931. tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCert)
  2932. client, err := getFTPClient(u, true, tlsConfig)
  2933. if assert.NoError(t, err) {
  2934. err = checkBasicFTP(client)
  2935. assert.NoError(t, err)
  2936. err := client.Quit()
  2937. assert.NoError(t, err)
  2938. }
  2939. user, _, err := httpdtest.GetUserByUsername(tlsClient1Username, http.StatusOK)
  2940. assert.NoError(t, err)
  2941. // test login with an existing user
  2942. client, err = getFTPClient(user, true, tlsConfig)
  2943. if assert.NoError(t, err) {
  2944. err = checkBasicFTP(client)
  2945. assert.NoError(t, err)
  2946. err := client.Quit()
  2947. assert.NoError(t, err)
  2948. }
  2949. u.Username = tlsClient2Username
  2950. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  2951. assert.NoError(t, err)
  2952. _, err = getFTPClient(u, true, tlsConfig)
  2953. if assert.Error(t, err) {
  2954. assert.Contains(t, err.Error(), "does not match username")
  2955. }
  2956. user2, _, err := httpdtest.GetUserByUsername(tlsClient2Username, http.StatusOK)
  2957. assert.NoError(t, err)
  2958. _, err = httpdtest.RemoveUser(user2, http.StatusOK)
  2959. assert.NoError(t, err)
  2960. err = os.RemoveAll(user2.GetHomeDir())
  2961. assert.NoError(t, err)
  2962. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  2963. assert.NoError(t, err)
  2964. err = os.RemoveAll(user.GetHomeDir())
  2965. assert.NoError(t, err)
  2966. err = dataprovider.Close()
  2967. assert.NoError(t, err)
  2968. err = config.LoadConfig(configDir, "")
  2969. assert.NoError(t, err)
  2970. providerConf = config.GetProviderConf()
  2971. err = dataprovider.Initialize(providerConf, configDir, true)
  2972. assert.NoError(t, err)
  2973. err = os.Remove(preLoginPath)
  2974. assert.NoError(t, err)
  2975. }
  2976. func TestNestedVirtualFolders(t *testing.T) {
  2977. u := getTestUser()
  2978. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  2979. assert.NoError(t, err)
  2980. u = getTestSFTPUser()
  2981. mappedPathCrypt := filepath.Join(os.TempDir(), "crypt")
  2982. folderNameCrypt := filepath.Base(mappedPathCrypt)
  2983. vdirCryptPath := "/vdir/crypt"
  2984. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  2985. BaseVirtualFolder: vfs.BaseVirtualFolder{
  2986. Name: folderNameCrypt,
  2987. FsConfig: vfs.Filesystem{
  2988. Provider: sdk.CryptedFilesystemProvider,
  2989. CryptConfig: vfs.CryptFsConfig{
  2990. Passphrase: kms.NewPlainSecret(defaultPassword),
  2991. },
  2992. },
  2993. MappedPath: mappedPathCrypt,
  2994. },
  2995. VirtualPath: vdirCryptPath,
  2996. })
  2997. mappedPath := filepath.Join(os.TempDir(), "local")
  2998. folderName := filepath.Base(mappedPath)
  2999. vdirPath := "/vdir/local"
  3000. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  3001. BaseVirtualFolder: vfs.BaseVirtualFolder{
  3002. Name: folderName,
  3003. MappedPath: mappedPath,
  3004. },
  3005. VirtualPath: vdirPath,
  3006. })
  3007. mappedPathNested := filepath.Join(os.TempDir(), "nested")
  3008. folderNameNested := filepath.Base(mappedPathNested)
  3009. vdirNestedPath := "/vdir/crypt/nested"
  3010. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  3011. BaseVirtualFolder: vfs.BaseVirtualFolder{
  3012. Name: folderNameNested,
  3013. MappedPath: mappedPathNested,
  3014. },
  3015. VirtualPath: vdirNestedPath,
  3016. QuotaFiles: -1,
  3017. QuotaSize: -1,
  3018. })
  3019. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  3020. assert.NoError(t, err)
  3021. client, err := getFTPClient(sftpUser, false, nil)
  3022. if assert.NoError(t, err) {
  3023. err = checkBasicFTP(client)
  3024. assert.NoError(t, err)
  3025. testFilePath := filepath.Join(homeBasePath, testFileName)
  3026. testFileSize := int64(65535)
  3027. err = createTestFile(testFilePath, testFileSize)
  3028. assert.NoError(t, err)
  3029. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  3030. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  3031. assert.NoError(t, err)
  3032. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  3033. assert.NoError(t, err)
  3034. err = ftpUploadFile(testFilePath, path.Join("/vdir", testFileName), testFileSize, client, 0)
  3035. assert.NoError(t, err)
  3036. err = ftpDownloadFile(path.Join("/vdir", testFileName), localDownloadPath, testFileSize, client, 0)
  3037. assert.NoError(t, err)
  3038. err = ftpUploadFile(testFilePath, path.Join(vdirPath, testFileName), testFileSize, client, 0)
  3039. assert.NoError(t, err)
  3040. err = ftpDownloadFile(path.Join(vdirPath, testFileName), localDownloadPath, testFileSize, client, 0)
  3041. assert.NoError(t, err)
  3042. err = ftpUploadFile(testFilePath, path.Join(vdirCryptPath, testFileName), testFileSize, client, 0)
  3043. assert.NoError(t, err)
  3044. err = ftpDownloadFile(path.Join(vdirCryptPath, testFileName), localDownloadPath, testFileSize, client, 0)
  3045. assert.NoError(t, err)
  3046. err = ftpUploadFile(testFilePath, path.Join(vdirNestedPath, testFileName), testFileSize, client, 0)
  3047. assert.NoError(t, err)
  3048. err = ftpDownloadFile(path.Join(vdirNestedPath, testFileName), localDownloadPath, testFileSize, client, 0)
  3049. assert.NoError(t, err)
  3050. err = client.Quit()
  3051. assert.NoError(t, err)
  3052. err = os.Remove(testFilePath)
  3053. assert.NoError(t, err)
  3054. err = os.Remove(localDownloadPath)
  3055. assert.NoError(t, err)
  3056. }
  3057. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  3058. assert.NoError(t, err)
  3059. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  3060. assert.NoError(t, err)
  3061. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderNameCrypt}, http.StatusOK)
  3062. assert.NoError(t, err)
  3063. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  3064. assert.NoError(t, err)
  3065. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderNameNested}, http.StatusOK)
  3066. assert.NoError(t, err)
  3067. err = os.RemoveAll(mappedPathCrypt)
  3068. assert.NoError(t, err)
  3069. err = os.RemoveAll(mappedPath)
  3070. assert.NoError(t, err)
  3071. err = os.RemoveAll(mappedPathNested)
  3072. assert.NoError(t, err)
  3073. err = os.RemoveAll(localUser.GetHomeDir())
  3074. assert.NoError(t, err)
  3075. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  3076. assert.Eventually(t, func() bool { return common.Connections.GetClientConnections() == 0 }, 1000*time.Millisecond,
  3077. 50*time.Millisecond)
  3078. }
  3079. func checkBasicFTP(client *ftp.ServerConn) error {
  3080. _, err := client.CurrentDir()
  3081. if err != nil {
  3082. return err
  3083. }
  3084. err = client.NoOp()
  3085. if err != nil {
  3086. return err
  3087. }
  3088. _, err = client.List(".")
  3089. if err != nil {
  3090. return err
  3091. }
  3092. return nil
  3093. }
  3094. func ftpUploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *ftp.ServerConn, offset uint64) error {
  3095. srcFile, err := os.Open(localSourcePath)
  3096. if err != nil {
  3097. return err
  3098. }
  3099. defer srcFile.Close()
  3100. if offset > 0 {
  3101. err = client.StorFrom(remoteDestPath, srcFile, offset)
  3102. } else {
  3103. err = client.Stor(remoteDestPath, srcFile)
  3104. }
  3105. if err != nil {
  3106. return err
  3107. }
  3108. if expectedSize > 0 {
  3109. size, err := client.FileSize(remoteDestPath)
  3110. if err != nil {
  3111. return err
  3112. }
  3113. if size != expectedSize {
  3114. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", size, expectedSize)
  3115. }
  3116. }
  3117. return nil
  3118. }
  3119. func ftpDownloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *ftp.ServerConn, offset uint64) error {
  3120. downloadDest, err := os.Create(localDestPath)
  3121. if err != nil {
  3122. return err
  3123. }
  3124. defer downloadDest.Close()
  3125. var r *ftp.Response
  3126. if offset > 0 {
  3127. r, err = client.RetrFrom(remoteSourcePath, offset)
  3128. } else {
  3129. r, err = client.Retr(remoteSourcePath)
  3130. }
  3131. if err != nil {
  3132. return err
  3133. }
  3134. defer r.Close()
  3135. written, err := io.Copy(downloadDest, r)
  3136. if err != nil {
  3137. return err
  3138. }
  3139. if written != expectedSize {
  3140. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", written, expectedSize)
  3141. }
  3142. return nil
  3143. }
  3144. func getFTPClientImplicitTLS(user dataprovider.User) (*ftp.ServerConn, error) {
  3145. ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
  3146. tlsConfig := &tls.Config{
  3147. ServerName: "localhost",
  3148. InsecureSkipVerify: true, // use this for tests only
  3149. MinVersion: tls.VersionTLS12,
  3150. }
  3151. ftpOptions = append(ftpOptions, ftp.DialWithTLS(tlsConfig))
  3152. ftpOptions = append(ftpOptions, ftp.DialWithDisabledEPSV(true))
  3153. client, err := ftp.Dial(ftpSrvAddrTLS, ftpOptions...)
  3154. if err != nil {
  3155. return nil, err
  3156. }
  3157. pwd := defaultPassword
  3158. if user.Password != "" {
  3159. pwd = user.Password
  3160. }
  3161. err = client.Login(user.Username, pwd)
  3162. if err != nil {
  3163. return nil, err
  3164. }
  3165. return client, err
  3166. }
  3167. func getFTPClient(user dataprovider.User, useTLS bool, tlsConfig *tls.Config) (*ftp.ServerConn, error) {
  3168. ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
  3169. if useTLS {
  3170. if tlsConfig == nil {
  3171. tlsConfig = &tls.Config{
  3172. ServerName: "localhost",
  3173. InsecureSkipVerify: true, // use this for tests only
  3174. MinVersion: tls.VersionTLS12,
  3175. }
  3176. }
  3177. ftpOptions = append(ftpOptions, ftp.DialWithExplicitTLS(tlsConfig))
  3178. }
  3179. client, err := ftp.Dial(ftpServerAddr, ftpOptions...)
  3180. if err != nil {
  3181. return nil, err
  3182. }
  3183. pwd := defaultPassword
  3184. if user.Password != "" {
  3185. pwd = user.Password
  3186. }
  3187. err = client.Login(user.Username, pwd)
  3188. if err != nil {
  3189. return nil, err
  3190. }
  3191. return client, err
  3192. }
  3193. func waitTCPListening(address string) {
  3194. for {
  3195. conn, err := net.Dial("tcp", address)
  3196. if err != nil {
  3197. logger.WarnToConsole("tcp server %v not listening: %v", address, err)
  3198. time.Sleep(100 * time.Millisecond)
  3199. continue
  3200. }
  3201. logger.InfoToConsole("tcp server %v now listening", address)
  3202. conn.Close()
  3203. break
  3204. }
  3205. }
  3206. func waitNoConnections() {
  3207. time.Sleep(50 * time.Millisecond)
  3208. for len(common.Connections.GetStats()) > 0 {
  3209. time.Sleep(50 * time.Millisecond)
  3210. }
  3211. }
  3212. func getTestGroup() dataprovider.Group {
  3213. return dataprovider.Group{
  3214. BaseGroup: sdk.BaseGroup{
  3215. Name: "test_group",
  3216. Description: "test group description",
  3217. },
  3218. }
  3219. }
  3220. func getTestUser() dataprovider.User {
  3221. user := dataprovider.User{
  3222. BaseUser: sdk.BaseUser{
  3223. Username: defaultUsername,
  3224. Password: defaultPassword,
  3225. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  3226. Status: 1,
  3227. ExpirationDate: 0,
  3228. },
  3229. }
  3230. user.Permissions = make(map[string][]string)
  3231. user.Permissions["/"] = allPerms
  3232. return user
  3233. }
  3234. func getTestSFTPUser() dataprovider.User {
  3235. u := getTestUser()
  3236. u.Username = u.Username + "_sftp"
  3237. u.FsConfig.Provider = sdk.SFTPFilesystemProvider
  3238. u.FsConfig.SFTPConfig.Endpoint = sftpServerAddr
  3239. u.FsConfig.SFTPConfig.Username = defaultUsername
  3240. u.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword)
  3241. return u
  3242. }
  3243. func getTestUserWithHTTPFs() dataprovider.User {
  3244. u := getTestUser()
  3245. u.FsConfig.Provider = sdk.HTTPFilesystemProvider
  3246. u.FsConfig.HTTPConfig = vfs.HTTPFsConfig{
  3247. BaseHTTPFsConfig: sdk.BaseHTTPFsConfig{
  3248. Endpoint: fmt.Sprintf("http://127.0.0.1:%d/api/v1", httpFsPort),
  3249. Username: defaultHTTPFsUsername,
  3250. },
  3251. }
  3252. return u
  3253. }
  3254. func getExtAuthScriptContent(user dataprovider.User) []byte {
  3255. extAuthContent := []byte("#!/bin/sh\n\n")
  3256. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%v\"; then\n", user.Username))...)
  3257. u, _ := json.Marshal(user)
  3258. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  3259. extAuthContent = append(extAuthContent, []byte("else\n")...)
  3260. extAuthContent = append(extAuthContent, []byte("echo '{\"username\":\"\"}'\n")...)
  3261. extAuthContent = append(extAuthContent, []byte("fi\n")...)
  3262. return extAuthContent
  3263. }
  3264. func getPreLoginScriptContent(user dataprovider.User, nonJSONResponse bool) []byte {
  3265. content := []byte("#!/bin/sh\n\n")
  3266. if nonJSONResponse {
  3267. content = append(content, []byte("echo 'text response'\n")...)
  3268. return content
  3269. }
  3270. if len(user.Username) > 0 {
  3271. u, _ := json.Marshal(user)
  3272. content = append(content, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  3273. }
  3274. return content
  3275. }
  3276. func getExitCodeScriptContent(exitCode int) []byte {
  3277. content := []byte("#!/bin/sh\n\n")
  3278. content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...)
  3279. return content
  3280. }
  3281. func createTestFile(path string, size int64) error {
  3282. baseDir := filepath.Dir(path)
  3283. if _, err := os.Stat(baseDir); errors.Is(err, fs.ErrNotExist) {
  3284. err = os.MkdirAll(baseDir, os.ModePerm)
  3285. if err != nil {
  3286. return err
  3287. }
  3288. }
  3289. content := make([]byte, size)
  3290. _, err := rand.Read(content)
  3291. if err != nil {
  3292. return err
  3293. }
  3294. return os.WriteFile(path, content, os.ModePerm)
  3295. }
  3296. func writeCerts(certPath, keyPath, caCrtPath, caCRLPath string) error {
  3297. err := os.WriteFile(certPath, []byte(ftpsCert), os.ModePerm)
  3298. if err != nil {
  3299. logger.ErrorToConsole("error writing FTPS certificate: %v", err)
  3300. return err
  3301. }
  3302. err = os.WriteFile(keyPath, []byte(ftpsKey), os.ModePerm)
  3303. if err != nil {
  3304. logger.ErrorToConsole("error writing FTPS private key: %v", err)
  3305. return err
  3306. }
  3307. err = os.WriteFile(caCrtPath, []byte(caCRT), os.ModePerm)
  3308. if err != nil {
  3309. logger.ErrorToConsole("error writing FTPS CA crt: %v", err)
  3310. return err
  3311. }
  3312. err = os.WriteFile(caCRLPath, []byte(caCRL), os.ModePerm)
  3313. if err != nil {
  3314. logger.ErrorToConsole("error writing FTPS CRL: %v", err)
  3315. return err
  3316. }
  3317. return nil
  3318. }
  3319. func generateTOTPPasscode(secret string, algo otp.Algorithm) (string, error) {
  3320. return totp.GenerateCodeCustom(secret, time.Now(), totp.ValidateOpts{
  3321. Period: 30,
  3322. Skew: 1,
  3323. Digits: otp.DigitsSix,
  3324. Algorithm: algo,
  3325. })
  3326. }
  3327. func startHTTPFs() {
  3328. go func() {
  3329. if err := httpdtest.StartTestHTTPFs(httpFsPort); err != nil {
  3330. logger.ErrorToConsole("could not start HTTPfs test server: %v", err)
  3331. os.Exit(1)
  3332. }
  3333. }()
  3334. waitTCPListening(fmt.Sprintf(":%d", httpFsPort))
  3335. }