diff --git a/apps/user_ldap/appinfo/signature.json b/apps/user_ldap/appinfo/signature.json new file mode 100644 index 0000000000000..3aa4827fc96fd --- /dev/null +++ b/apps/user_ldap/appinfo/signature.json @@ -0,0 +1,407 @@ +{ + "hashes": { + "ajax\/clearMappings.php": "b13727cfaf56e4f09325eb84981961144608e91bcc9fc433de91c2eea324cc414fd6f96958123f18b27ea169944999c6ecbd0be6aa1d669172494f8c979ace48", + "ajax\/deleteConfiguration.php": "f9ab4f01c6c731e3a4d6907f05233b113972da205442854ba9d2656fea6104682542bfa52c00b893de283f3a9b2db8a0db0b38730e383546ff5689903701231d", + "ajax\/getConfiguration.php": "58c8ddc9e654743d79a40ff3299f138af2e690afbc2d46f037a7258f414182101a80dd23997cc7a2ddec68eeb4f8453d36992386c4f3c11ad1cf7ec275565a8d", + "ajax\/getNewServerConfigPrefix.php": "8c1cac236e615fe118b0060f2aaa03f79335b47234bf633f9f54b9f707598a4c9db22b41a83eb3a69b2dd86b9b60a3ee12f2f0cb2b7b92b71968183cebf9afa0", + "ajax\/setConfiguration.php": "a9b42b86d15dfe19b98cf879ae7c99efb3528089a5b79cf1817cd75c62138b2861b710d9f471551a882a8e866ae01b75d9823ab43992823333bc2fda8dd80fbc", + "ajax\/testConfiguration.php": "0895b234eef60fe1441c813fb72d94e8df6edb329dfe01dfce2242ad879600c6345628d97715eb1ae156e035f5ea0006cc5c8c016ef30c2cece64218dbb24f01", + "ajax\/wizard.php": "243965b131dba7182c77c383ca3b92a553186ee47c02bad723b916571e8fe2dd9d2e77d0adb07e519826a0f0007bdc928ce2d2ae282e1e6df43357243becaabe", + "appinfo\/info.xml": "69ab57071c80d50828cfce32d38fa97eed10e85ad71d26b3a96e1558bd3340961a749f5abfd7a7ecdbc311d8dc42a42990d70268375b21d98451ae46c3014aae", + "appinfo\/install.php": "1e8702f937a03034f57003ef1204dc93e7442f31df1174748c9a387069614ca79ebde7cf766d80c10e808c7ce589bfd7ead02daf8f13ceefc98b7450ac395122", + "appinfo\/register_command.php": "34c593226f6d68f812e6276f47f8636a66a60cce06d04cbaa38a0bc3e0d9c82f99c48949daf02953be3dddd5a608bdad43ec0124cc36104f8c42cb6c8f137b58", + "appinfo\/routes.php": "a57a4168e9b349763b7e953b15ef3909aa453b6c06514f5d4089ed653bb6aa7eb8e2681c3acecf76336cc793108911db31f4136f45cfdb0cda0c13680355651e", + "appinfo\/update.php": "8ae9fff2a64e7340d4f3981177abc6e44f9a9299f3d663b95dea8fd6e09e75c32907d4e096bad9416ca44e5a4e4761fa78e4de4820342efd6c09e6e2a086432e", + "composer\/autoload.php": "76a3962dca96dee4ac0e1afbaf670dcdd9379e8cc9481f9c2195dec5d86f0c2b2c4105bcce7173db4c8c5e039870d420603f0eb34ccadbdd69e3b8b8574368bd", + "composer\/composer.json": "3df63a6d4ea53ac3fcd1ab4a33620587353739d45e9d891e169ba515d1f74f5d0f10fe3fad84c64ce894c61c71c6450294c857d8cd2a4ab05dbd3548e3ef37fc", + "composer\/composer\/ClassLoader.php": "e95f90be793a521568a3bbe14f724e47f58173b8ed8c7907f799932fd9ef483ac4b9e741b572a0867a1afdba0c96fe7eb919980df240e158313286e4979cc66a", + "composer\/composer\/LICENSE": "f3bb64009f41a425df5a9bbab53490f0eb9b74fa8d6aaa2f57efb928edc4ffff330260666edeaa04a91fed708c3663371cf01b284f3a08d6698aaef7a23f355a", + "composer\/composer\/autoload_classmap.php": "c6b7703804928f9b33c3f33a58d236fcb2a578d421e079e80dd2e275b602d14639d1efb0a850a2d419e3b86d1f66b14748d087b0ffa5270f920082306d04d776", + "composer\/composer\/autoload_namespaces.php": "dd8ee31d2faa9014fe567e1f954b5e7f450cf06feacbb96d4df663c59b1a36a0b7d26ad41b46354bd14f282fa7899298137208d1851099cd3ada285650efd90f", + "composer\/composer\/autoload_psr4.php": "9558aee131a3748c0fb48ec8c91b5145638f33866d128433940d5fce1d584b811508db062099eeb0336fd0bf89a8760118ec43a1cfedc468633261be59aa1cdf", + "composer\/composer\/autoload_real.php": "2f121adb87f9dbcf9ea26239267c84252d0ccd469b8534c162848dae9f0cec237a83da59888cbd3eab4fcea0ea82a5d916d0dfb0b9e8e2381fb55da235e56018", + "composer\/composer\/autoload_static.php": "8e7d23dbfc8cee70bda5550c26e4da624f3c86708b546df0fa062cae6cf79be21459090b55b919bf67465982c1f8a8ac8a37cd8b8f0f3a790afde155ba687c7c", + "css\/renewPassword.css": "94c76430e2dcfbf27614113dd7caecf0a213d695318eb267c8c20e6ff107ea261905d8ae926073a15524c419924dab5951fc3f11e188b4a0277a54f7d826b8a6", + "css\/settings.css": "e4597900a692c046083a6b41be705778f4f163b42a9009b4b70a44707a18151f855f072c98b9ddef5e514ddf3ec7fcf36a0a41c0b8548144376bdf238bb0ea1c", + "img\/app-dark.svg": "de427b31679703fe33d206a8d071f051699dd08bb97cc36b7e0788004a6ad6baca58b57261aa33f52e3cdec7d2e21fb6ec2a4d016ae65bee66de49da48fcece4", + "img\/app.svg": "5c8be35c5076766bfd5718a92e4d05ca37e79732ec12f760886af84c8923224d347b1f9d9d6c1e94c48ba90858b4f4d4538bdaeb768272a2ba281c5c77a244d9", + "img\/copy.png": "6303e225dde6a1ed8d14dd2d441f9cb7ef2efa06ba5e2e91070459b93132213d2104901270dda099230f45ff513731991b869dfc4ee02393b07111a1f641cbf9", + "img\/copy.svg": "0d18f4de308dffe78a728a9777339efdc4126f85c6d2c2384c13609745f765620f990e2734cfbd9cd7d522e0c9ca62d3c2975641ce69f17976499dc254c56d45", + "js\/renewPassword.js": "509ca8b3ca5824c23210595ddf2aa1d2f38bf9aa28475f5618d18e081b5ff298a03189cd19f1ddb6b7f814845592b4c9675100a56e8a73490075da3c8cf7d1fd", + "js\/wizard\/configModel.js": "e6bffe941992874a9898300eb043aa6bf8fb81845869ff4301a07553bf67590f3960be6dc2c63bcd071024a10c5ae8d7d9284b5db83374b9b3f486d2cb383760", + "js\/wizard\/controller.js": "831dc868fc1ed9cc890214c7d8a9537d8e20ccae56a1c2cc5a8177acfbf3aa569597f51ff72038adf2de917eb762f69a61b7e9d6bca2e135bf5c980cc23ac933", + "js\/wizard\/view.js": "440ef11cd1c8503499dc4d125f574d07e7851ba6ffefb3c90752ed3924fe77e6067e465192c8bb0903e46a73ee4d3cd812b430d5806eacdb9a1b40ab4cdd9a53", + "js\/wizard\/wizard.js": "80032cbe47052bee60f54fe48995c70e19d07b2c0164fc8cdc804201619fe159c1451aa8de3863eb25ce988a3aca4fed7a21dac2a9961f80a461c67f0d4643fb", + "js\/wizard\/wizardDetectorAvailableAttributes.js": "770526bdceda18fec8fe5f1b7b3ce871a1928264091864834b612afbeeb98d020e9f769ed5873c63709e41a50d2605055ff4e992770c8b2760bf1118a1c87de2", + "js\/wizard\/wizardDetectorBaseDN.js": "88e9c3fa81a98198f4865e9a5024e5b5b35540eb2fe9032e6d8e90e4bdaed06432be69e3087099db1301e09b0ef72e49dc28cdf7e979863282576ce3b61f006a", + "js\/wizard\/wizardDetectorClearGroupMappings.js": "b43b6bcf2f476206055a24f887247ae0e5615382fbc586223518ce8836fe899eb4fa5d3993c12b714a3adb8d4eeb7f77200dd4408344e0e629702c8b7fb7b910", + "js\/wizard\/wizardDetectorClearUserMappings.js": "7e49a02453d17edf4216ac4f8d1a20529db500fe64dee1aaf2e4502fe60de88510957212c2a8fe246e38ae27180d64c386358910ff2f3dc6b7486d82d66bc6cc", + "js\/wizard\/wizardDetectorEmailAttribute.js": "f6f3723aab647fa6a2f38a52a34a29ff1f89126698039b4090919486c60a69a6f0dd62fc7e5458d7a1991172f5b1a1afb5380b7e8ef09f293dad474f7684fa0c", + "js\/wizard\/wizardDetectorFeatureAbstract.js": "730b67df59068523c892f3148c55abc6408461b3c9b72976574c83866b11298368447cbc897d0237f4b5ce94052c1084d3cf2407d4843ada43af4799c206554e", + "js\/wizard\/wizardDetectorFilterGroup.js": "c2cee452b2a91a84d0fae2054648b5720ee4d863b7233190a3b6bb54f82499c0e2d7f08a134d467044920149b3c47f5a9e1dbca22292bdca0732c2199b53004f", + "js\/wizard\/wizardDetectorFilterLogin.js": "8b0c6b6b05bf2e4b4c94fbd5f5e75659c12a732ee0df51f3248660cdadbe630bd2e4cc54a03724c7befeb89e2c2b54fb2a3860d3fb338bc3f8f7bbcff4662a31", + "js\/wizard\/wizardDetectorFilterUser.js": "af7d0a80e34012152e6e7f9f0f0edbbdf36a364bc693800bd9791205d6c8fd809afac9cd5f8f965f96491c40bcb8e6a02162ad73b07a12b4809ddbb22cb06f4d", + "js\/wizard\/wizardDetectorGeneric.js": "cc4dc083ec3529c5316051be091367fd66a8e8b9499bcd491dc26f831bb8582219b7e9be6517e95a52872939855d118ed17c6dc376ed2c440ca5a91861c9a926", + "js\/wizard\/wizardDetectorGroupCount.js": "47fddf38c98ed7d165d034f9367370dea3b5b00f1c57c2bc57554a53a64c4010e80e813409c64409f04bbfacaa64d10a12ed2c686b06f9734fa4b754627cb221", + "js\/wizard\/wizardDetectorGroupObjectClasses.js": "b898927813e56fb6be073bd1b2307ce0d28d5ff96ec158ffc9b7b8c3ccc47e0be8dce2eb4d940dc1954eafb7af5c611a0fa0c456b1ea89ee755a56414b44538a", + "js\/wizard\/wizardDetectorGroupsForGroups.js": "af88cd6550dca7cb3aec7b15640de0e54d6b58ae9b6c3b9004951bc23ee57ecebedc93b2d423efc822a45aeea9b05290888565381e1e0c7969ade90d2ebbdc57", + "js\/wizard\/wizardDetectorGroupsForUsers.js": "848df2ea9ce6b2f5d5c9ea2ae488b5978fff6ad88e917a3a7b7de5c3ab6e58dd2c33cf2f945463df648ff7d4a9cc735520643a3dcc7c802a3340ae0f373bf722", + "js\/wizard\/wizardDetectorPort.js": "c59500df1898bace884ef067254efe4d62456687d75f2bd626c74545163845972d911c1a766aa980fd4c13be644b7f28ac0793c43cf6d5ed3d068c282c9f202d", + "js\/wizard\/wizardDetectorQueue.js": "55e826710e56d073fe68a3ec9865a2939384b78bf1e00e18291ee49ad5c9aa741bb12c7a24d59895d89be255b2a8c8a2b544403d9eaea5a2b14a12679dbdc587", + "js\/wizard\/wizardDetectorSimpleRequestAbstract.js": "7985a8dcae3d662477e30e4c4cd6b10768a0eadf2b29f0760c4e66658e0a44a30e18ec23b098b27d24c8d6f00ddf7558639886c4f82f1e2cd651a799992f69bc", + "js\/wizard\/wizardDetectorTestAbstract.js": "723ad0ca8d5c7279cf83d0cfa809cd9a141a5b015a2f23255bbca40e89c79aef8e5b7a4f4ba1fefa2155dd3f2815a6036be8dacc2a35082e91214252d713d22b", + "js\/wizard\/wizardDetectorTestBaseDN.js": "fdaad3843ce8767bfa9525359142c9e54636d629d45b9b7d082f69b791a3081a16e5c4939fe441bba2eef4b604c0072ac2319a090a82a7fa54362f829afb7a6f", + "js\/wizard\/wizardDetectorTestConfiguration.js": "27b50b7564e58478f1e7a1b1918db26231170bd6264b812ec6047c1e313d640914e3fad568d8aed2b2a01be317e9d315752d26f42b7d7662ac8526c288ded009", + "js\/wizard\/wizardDetectorTestLoginName.js": "002517d45aea4e7456ceac1c6add1f52b3a79df52af0ef0e1fffab84ce59f858d33334b33d7a4fda2b936883e8ac5986eca933b55e705f850e0ac06116a3420a", + "js\/wizard\/wizardDetectorUserCount.js": "ac37b9bd82046afca6211a9c8daa3cc5abe59010c9266ece0ef7b6343ed2ee6448b41669b2698f228f87d0abe41a6b9ac0a22a5bc279f9af8ba6de4aeea3a8fd", + "js\/wizard\/wizardDetectorUserDisplayNameAttribute.js": "3c5b50c881d61ae7f98a48bfa5ebd0de02435f3475f8c5dd5f3c2f8bf11ecb5a177efcf4759bd069ed896350cecf430b35730fa8163c1b3f39595021490e00b0", + "js\/wizard\/wizardDetectorUserGroupAssociation.js": "595578d2a2ce0f7ceaf3e702536d429b65a75419823f54c00bc10f4f92a32fe4513d0e53447798372f94bd416cacc2d2a1015eedb647e58af6fa49ec950b5fca", + "js\/wizard\/wizardDetectorUserObjectClasses.js": "33dc057794b5ff169a830ca735f09c86beda21b0d166f15f1870006c5bde25fdf2ca02ccf936a51400b2873d27da95039f227bcf63d3844d8b272fe75f726cd2", + "js\/wizard\/wizardFilterOnType.js": "44f8424bdff5d5af5b34d52ba8e719a7cef8331d49a414c326a6ece727210b3846d37867f7bc9846e7a4897529ccf95121a2106d19ca7c3f05b885252ba36a6c", + "js\/wizard\/wizardFilterOnTypeFactory.js": "e4a167d6b4c2db7630defe05b944a38d8ee4fd358cc9b5c206391e5fe4fe35237e08f3bb511138be16fc21a5fbce6d54b55c8ec9b03ccdd33fdee250f55b989f", + "js\/wizard\/wizardObject.js": "d76fce9ea1abd4618012113bb9eb92e0e35de8277895d7e45f5cb616eec2c634078fe3ce6a41dc3b4f46c64240d9e831b0ce48906fd10a7172c15a5ff9833d29", + "js\/wizard\/wizardTabAbstractFilter.js": "678ebdf4163aa0c41a7837e7640a5afb8cd6e64cc910b21e048a1bc7264d2b7614290881b8ff1286376de68ad75b7dd4a7dd6759165bf6a7db03eaae5b892b9c", + "js\/wizard\/wizardTabAdvanced.js": "4835f550ac89e4ff7bb86ce3f4329f5038f6133ff97a01ab3e59d019f4a4b44233320dbee05f9211363f0df1f9dac44be4226b3d0fb85eba5928457204d7512d", + "js\/wizard\/wizardTabElementary.js": "f2b1987dfb53b75c4433fd64136815b7f87a6e723034110bbe1f0454fc9d459ecbc22545373f09d0f357116b18244085896bccdf92fc5f80e1a267bcd94447bc", + "js\/wizard\/wizardTabExpert.js": "a4a25c894bf9cb9cc3c46812c43cb3bfe1d5fd7ba37bc634c24be40c6c413cd29468b2d36c2c61c29ed6c3579e92800e28cd53f0fe81ff2702c9ee65bc40514b", + "js\/wizard\/wizardTabGeneric.js": "c291f2db3eaca5be532306674a11dcd0e47f28c1633f9e500aca66f6ae07f5845eafdc78efd813db037e81fed94c6ee87bfc375ed6b2ef5f5dda5ddbd60913e6", + "js\/wizard\/wizardTabGroupFilter.js": "1d8577373d5f68cb49234155553f4f9af631604bd02b57c25416f500086170b7ac8a579c82e8ed4dd9bad46ae6ec2a6b258555458870c0438d814e96e5f96b37", + "js\/wizard\/wizardTabLoginFilter.js": "645ac27c059c9f4dcac94aa16da834c873e08eca2ffa18d17569ad5aec968059d253c8081fdf8b3c813f5e8ba157e979285807120e8242345b95826623b40515", + "js\/wizard\/wizardTabUserFilter.js": "1d81ec356bc1b948762123098a52f862c642ae6a0617251bfe167bda4073a57fa619dd2be40148ce938ab245fe48178e743d85c8f47025bacc75aa07ffb9e8dd", + "l10n\/ach.js": "584616c60777f992280413b3849fd779c5f8e1b4da2f4cbd3864dc35842550e01076fad35a6f95ebed4f32436db05e70f613e95e676a83add0e36232b922a0f8", + "l10n\/ach.json": "f3711573f0f71802cb423dd9c506c602996a7fbaab151df96a39f5049ef4f15617fc771d71766cca8f22e50ce5c5319f4438add093fdd0a1b73c5344d8c34348", + "l10n\/ady.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/ady.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/af_ZA.js": "edb03a848a0d3a0b70c6e53c48169455bbbdf3d853c61b21abd06eccb9ab01a7457ae17ed07d5627e7858259a52467f1f06ceca071c3cd5e86b41aea7ae1a24a", + "l10n\/af_ZA.json": "b4b000b3eff34c4f6bde514baa7c563edb710ee1e3aa68ed2cc94a30b72118b09801606e1760c437b288f9172453a2d2c38f84cfde23ca3f39b1c3fd243aad6f", + "l10n\/ak.js": "684c1f70d99dabf5d979146e9cfbfea53c084a1fefd9c6a0c554f5a791822a88782f10011ae52634ef3d563a070e870d108f30705a47dab9e9498b92660ecfd5", + "l10n\/ak.json": "fdedcbc0ac85c73ec9e5121f515df2b2a2a35a08c0bec811d2e4672b7e609a6a348f062675c245767be3be16e4b5e54699fae6b5af07ce2d09324bab24669277", + "l10n\/am_ET.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/am_ET.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/ar.js": "722a73cef6e346c23d7a04b9e29ceb9fa91f6d92a6ae0e89d5722972a753dbd62f057704b1ca762315c2ada3d7afc227a3f4f1f988e671a12dfc9801f10632ff", + "l10n\/ar.json": "90691c6cbaebbc304979c248426a46ede9ebe7aadff04138dd83e0141f77218bbbd38f01869dc08da1215efb51d334dd662f96c1fc499339793e2ceb6ffac054", + "l10n\/ast.js": "8c208b78db277f8da280323dbf58b0359773fd906330b0fdf499dc677b244e674f7947820343e079da88337ce3e8106b6c4e7a62ef23d146aa5dc720eda0151b", + "l10n\/ast.json": "2ff61e52e5580d95d145710b04c2d53fea4e2fdea09d16fd5ee9ed8dd9edbd5116cf7c040fc65e1d41d74040f32588bd43441fd6ee15872c2ec1bbded8888b22", + "l10n\/az.js": "e3e2852fce6e2e87a0556f0370872eff673b7ea1483c0b483212bde0394a0ed8df4ca836de080d6a7e9f7778baf415a76ec03d4615ee2894d99407547d9c9d1e", + "l10n\/az.json": "14190932496abbc90e7ac934f0731e5b6b3d5982f27881a60a55136404cc97bfc6bb9e3528bd4cb7752545b14bab2b0b7e5a96d5eac7c8f5e9bf3633fe787d3c", + "l10n\/be.js": "5d6f40227af673a9289b7e2adddb328440fd3760481977281f7c1f2a8d04d4c4a8c75a7a843aa66f6aa8fa1153de4b40c7b8d781692d3036d4889b68ab34e26e", + "l10n\/be.json": "59c943178552b703fa989e3cc1c54a56205c0d8e1a1feb3cc4f1a88178eb289579814612f6bd884092d8540887dd1829e0cbd8c38f9557ca459f80cf7bdf5b56", + "l10n\/bg.js": "0e5e43e17003393df3cf71ffd2de1b6cbf256b20c1be4bd5b2f64aacf417e19d74dc021fb970e836c0c3fa4f7ce02c5ee9a37f26a56be4d38787eb110da83ed3", + "l10n\/bg.json": "3a9e4b0cc02f1640c7799b77fe9c46d99f12105a9e620fe03dc53903b2d20a4db8d48bc96131c01a22035fcf75b206dc5569cdac54faed8c63ce29f0db50a15a", + "l10n\/bg_BG.js": "2ec7cc4a257f4c0e6c4ea7a2e3e0520b97b88c9bb39c5a73e96dbae324f7c63382bf7483863b79b39fcbe1bc4324aaf8735a913d2cefd02e2e2452cfd3bc6e96", + "l10n\/bg_BG.json": "d6ae3f44ba4ceb85faf869254984aaa54d0827b686f4cc2e0434f3f8a5024d8a406865ca6c911e0b5a4d019c283fc055b6f02a24559537db7da1c5ef45fcc56f", + "l10n\/bn_BD.js": "b494e45b53a4c475ff98cdcb6f82a4b4fddf4b87443743baa8ccbb8cf0b4fa7992189a881aca90485e9ddfb3bfae6af60db6bbd1808d06e72bc91806039707e9", + "l10n\/bn_BD.json": "150e514eae5ff7dfc65366a9046da727552595ce9a0096d9a2543ed3505ff0ab07014e64354cbea5321b07be0bd4dd1074ae72810e52cfb9b22c76702c9de76f", + "l10n\/bn_IN.js": "dce780e83554e4e358b1f71d50b1f61c1c7fdde664f32bed016679cc342f99cafd5775d8ce1f83b6930712e42df978032d1874a0ef0d12440b66d5c3ccad5ac5", + "l10n\/bn_IN.json": "5f6839abb9432884a712f402909729f5f658e7405c91ed438ab2dfdcc9287d32a896f8547975c11d209f64e00383be8c224cbb3d232f1ce3e60e7b7ad451df28", + "l10n\/bs.js": "35af64cd9ec04e8ccd830539bd812534879505314a1c717752bae305f7280fded2e4cb3e91a28b5209436de780eb040d48fe443bd1427d0aae8b14b97f335123", + "l10n\/bs.json": "b452d8d5e32b4be8a224061d1a10c090bb6360f7a85ab370195d999cd4bd57cb1b3caafbdf2e0b78cdc4af4c0bd191a988bad41d7d637dfa762a8b4755d3226c", + "l10n\/ca.js": "7f1970d15bde6c238e52486959b9561cbb7eb404e065b3b7d3f2a5f5fb28fae08254577e96403798cfc31399584016e6ce5676e5ba3f4aeeea0bcb8d6d182b46", + "l10n\/ca.json": "c99f641bc07b69b135b710a36b99cba9cc8723781ab1d5e1fea9385e4eb4d8d4ecea2ae0b2ce272db182d70d1f79e678b6c32213cd7ecf8766c72f167e084069", + "l10n\/cs.js": "2172e1b28288977953991e113d23075ba76811bac09a82bd01e9d1bbd91605ac9bdfe5fbce173f03d2444b769f3e5e9f04cbbfb39c35a3b03711e847cb79a279", + "l10n\/cs.json": "36a35057bc4968fcfea18be71c528eb507032f6de624cd8fb37f040dc12b08f39960f48276f2416f939cc2a4057f1d00e8fd35203977b618bd934d1f86677f1b", + "l10n\/cs_CZ.js": "5479e2fab99711ea57ad9b77058f16035134a6536d1c6100bcb24fc222f5f2e8bdf5373d0cc01c1a190cec81681b566bccc8091877fa0f3e1834b0039fa31bbc", + "l10n\/cs_CZ.json": "dfbeddce0787fcfff9330ec4c5066c571a77f9ca4a3ff9f009e2899dfd4b8da6f0e9e594ad9a16c4319944a90a66a61755baf78319e326e4a46fa7ed6f42888b", + "l10n\/cy_GB.js": "44b83608ff038ae1af4991fff868f747288204437c28162de4785f78891815f6fadbba30973b83755a7c30616dd595bfe5d0bc1e7538120751e470ff24c4f1f4", + "l10n\/cy_GB.json": "9d583b7df484bd674ad4c76a3706588e56d252fe26ee40a757a01dc2a80960a53f366755be605441678d99487b4bda167e711520fe09482fede22a2798f1d9b1", + "l10n\/da.js": "de73f0241b84e8c37b8786dd3f2a245e4652f1dd29edb6f9dc278e1a0c11d0c20336e9147d59fe6a3fe952b4e444e82a9cf1a2c9c118ab7eef78f0f1a8a288f2", + "l10n\/da.json": "33df7cee64fdf40d2a88fa637995f294b502b6cae988cd6c017491d47e578aa31599adcd5795a6d885ecb5f2494fa5f36d49591ac465606251244ce045bde54c", + "l10n\/de.js": "fbd641e9f94db3e97c8a86c6a31dec9059a88940fd58efb58c8a5e9eba1df6511494cb58aa7e2df9f7c3164e80f1c0c8a8722173db107d9f23b2f5fa082beef8", + "l10n\/de.json": "4ce84e2d386a75af10f40625fb7dd5f20d8a0db6c127d93aa0a42a10b19f508f04097b9e53f476bc5278ff2af4a3d5428d1da1bcd2fea7cbd304b4a98fe281bf", + "l10n\/de_AT.js": "935c48fb9fcac9313972d69c9beec9dee7836b108392ce77a2c060fa3975c2932c9e351da9c14faa47d06c5e03793fb2708ccf0564119f4c1dda25f392e5a361", + "l10n\/de_AT.json": "448db53ae94b6a2b82714e574c5b41ea2b58fe783db77b591a11300664220c47e99406bb515f5b9615e43bf6baff792f3ac7b301cca07f551e1fae9884bbf191", + "l10n\/de_DE.js": "152337ba4398a54035f5486f37500a07d3f161a29cc0f3da6a14f4193607860d35010ab4fd738d217ff6c70769be7c77cc412d043d5cc27471e6b1766d0efedd", + "l10n\/de_DE.json": "bb220a355c1d1a99acf426517a5db2278b257bb2d75283eb433d826dd37a8c7940f843d6a5ad6a80f2b3170831a50251a9362557b3e52c47af027d423908c4fd", + "l10n\/el.js": "73744173946781e439f76eb5484f981d5a4e26a3d11e70cda50efdfc20d86a707c3c3ad336a7e5d293aa2d172b1085555addca002924ccb12f1b324d3e4d1cd7", + "l10n\/el.json": "2fe36a2c9e0fa582d6f04d2c3964780b05b0cebfb143651973b25a9dc362cb3639dc6c7ce1b4d8bd182fbed9afd782a62ce063fa7022bd34fe88c943ac80817b", + "l10n\/en_GB.js": "c5e830fdebacb1a122234384ebee1fb89218523f46e7d58b3499a2d9593323802dbbea3bb6971f4f1f1309c1619c072f7fc91e1894153092be16a905c83dd4e2", + "l10n\/en_GB.json": "63b2eac2b3b0eb4f763347469dd234583b659c26c56b9595c9e7a918d75d8b284fd3574d6f7c8e1a7abb3b3b48ae116c94deca4ba33d9d2fd342f546d46c0409", + "l10n\/eo.js": "4769be5b1e7e1d688db0ce7688a94735e4e02cf44066a54e4c1a4dbff986777c3589bdf6a781746cbee1023d73a752b8630a27ae1bae10a394ddaca537d319c5", + "l10n\/eo.json": "036d8e3864ba0697427c16671eb600cb64c46e5262d35af89e6b6dd97205e0a69d97f5f31cad9c97231c9cb35d25ba5c863425c0875680a66d54f434681c80c5", + "l10n\/es.js": "19fb9a3925ac7088735cc3e914bad4e655c228d9bbb254968ac6c350c4dba7be9bc8e9c5a7f4242a5ce8c71ab0a7dc31e94baa30814e018eeadd887f5ed0c4a2", + "l10n\/es.json": "41faf1a1a3d9bb80f524f0180d47adbe31c754f05159964ce3abc8f31670b1babb9d6850cc6899b618726ecca4e914063d16c5b149f263122f47cac6c15c3b07", + "l10n\/es_419.js": "21b666893116d3eccac0520c9364e144bdadc6459ef7213ac60374177eebf30029fa40ff083be8e064eb20919c26cf32f715415223edb5306811a63ab329afc4", + "l10n\/es_419.json": "ebb7e09c77402b01b1c737ba2be47b232d8d724ff0fd9a0473e1c7574d8d8fb29bfc2a27ec099c1381a0f2066fc94748d91cb8e67267cb2d7321e1a586660fe4", + "l10n\/es_AR.js": "9c0d8a0942ced3ae7f0f9b8e0f3c310d1d67658850e233ba8bea395b7008446a474daf095239c5a9dd50eace25a8d659e00c51c07943479b1a5d6b40dbecfe0b", + "l10n\/es_AR.json": "3142e5ed3ea004a2e8f7304ad8c92b513026cc3cfd095159b4de4c2c5cb0a41c8ea962663adcb8d7128ca5d3f5f3ab9f40f9249e28ea36369259ea3f01f31e1c", + "l10n\/es_CL.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_CL.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_CO.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_CO.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_CR.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_CR.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_DO.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_DO.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_EC.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_EC.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_GT.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_GT.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_HN.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_HN.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/es_MX.js": "1411e553bb73bdc7fff1a58f32c48f58fa0a4183e20921c1564b10ee6766bc31ac92c7cdbb1870174d5a4a5acb93f51d7dffb3bafbeeab01732e767345aa6ef4", + "l10n\/es_MX.json": "8f503a97d39a91f66f664b732b04d4779e081fdaa3a45571a9ac0191463e02a0ac6fa979fde434b2e05dfae46d08f5565586ab5a0e4a291dd70e14e4b4e95aa9", + "l10n\/es_NI.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_NI.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/es_PA.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_PA.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/es_PE.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_PE.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/es_PR.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_PR.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/es_PY.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_PY.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/es_SV.js": "7664b8affa1ceaf0a0f49d806635185bad0b1a9446505bfdbe47d0eddc76197c19983ed6bd90aaff4fc309319b8efb81478c78b2f338e8376e5ba919d9ed80e2", + "l10n\/es_SV.json": "a4f44ea57e5195ab3f859dfaf8509769de4741d05050a719e53b369924d1a60ac0ed74ff427af27e30dcf256071f14f84579fdadcffbbdfbe99dff4ef5879ddb", + "l10n\/es_UY.js": "84c1cb470619f5aaee8221aefc9d3c64c90d1491183c71f88dae423d193ca49b993b8b52a8ef2f9166ba901651826ece641d12151e0e1f61feb66048e7eb0c11", + "l10n\/es_UY.json": "954f70d6c3148c7ba762596f0bc78ffe0097d36fbd34d441e4010ae48e2eb2608f37fc400f1b59f2bc9289ae982f8813624b6c2a7bd2854d69cb2821e40dc4b3", + "l10n\/et_EE.js": "d19d3a90974cf7da770a94c6ae731260d0c1ed69bd553402d948dda9673cc55a635584fc0e7f7123e8e38dcf4c51cbbfbb92de3ad8db33a51f4cb795799eb842", + "l10n\/et_EE.json": "cb3ef5a466897cd634f1a7958fb148565866ad38522e3c263549c1b212d597c0bd233cadba093e2c801c16bdf588500f050e45dae6b26269eaff9aad8732c749", + "l10n\/eu.js": "c47d5cde2c8fb1bda6fb8449c611d24ee3d2f4b84a0f5b0040fafd9f2729b23b7b0e70dfe3a7c077054a071d4e8c03d74a96fbedfbe2d53ec37e37652f284f48", + "l10n\/eu.json": "56daffd076c4992b3fd2d6dfd990a286f1243f0018fc11f4f6e76fe5b0017b4c65aa24c5640390a9cbf44adc7ffe6cfee1f34b0202139e373bd964cd723b7735", + "l10n\/fa.js": "64c180334ca9205284a7fa587f10b4bad40519d8564b7b357fc829407b08a92afbbe0fc5468cbdec8e745fdad8a242ccca2aa5b782c5a29d48f8a10a4ac0fe73", + "l10n\/fa.json": "6b96b3e14967d5499a7ebe5cac45476a54454443a058bb87784ff03ffe49905a0bd109cf876ad9ab17ad299e7ca78e35e42d41117f60b3c1c72c2ffbef253762", + "l10n\/fi_FI.js": "5c12a666f25465b47ccb09f25ca2d57f8f1d2a671112eee61387c20b1de641e73eb2792c828e1f72c055ffb106133128e4cfa5eb9768d6bf6526e2927ff50f31", + "l10n\/fi_FI.json": "32780f122b51ba44e70c79729aca66518149107b15940ec3347859e1ab0a31db5a8bd18724cc59e074a2eaf0ef1aabae98679362fcf2258ebc48fe5ed44763fc", + "l10n\/fil.js": "c868f0f535d2a1d528705dc9795801d90a610d8c7a1f765aa370d92bd6c2e4e32172096da3adcf862bc531fce8dacd31c41b5dcca375df08d0657b4444ace76c", + "l10n\/fil.json": "7844263c6b9d31cfe8f123daf7a710f87ab3ae58f30d252625e3b78150f3099f16c7a37c9b0199fa695953efa2767eaa7f837f34df60df16c7da4138c2243af5", + "l10n\/fr.js": "4228bcdb639b31f6d103d4dabec98e6ee74c2e83098f0b30f82d1efac6e807d8bc079adeeab566f2ebe693a6ebdd93e2793dfe34d356dd8bb85fc46bd0eb4878", + "l10n\/fr.json": "cc62a016ff687a0b4d12ce5859ac4d3d853fa001be62b8176a0151081792a32e0f730dc9216ea55b38b5086e7aba62314e11506cabf6c215fb5a0a8bdaec43fe", + "l10n\/fy_NL.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/fy_NL.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/gl.js": "67d7f3bc6d807ec4189c8db50f96bf2779dc3952c531f3ec5f9f0b43e996e2f817850974096d65cd2c4cbcbe59264aef41546cdb398183deddde03f1061af2f5", + "l10n\/gl.json": "bf0972e27d91ba85ac0dd95be98febdd615497ed36a22549d07139a1b63382a2c3fd8a0e08e5fb556b9d251a11450a8aa0397f6f4fa4b74bba5aabf97acbdd08", + "l10n\/gu.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/gu.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/he.js": "494c4822c956d1121765a70ce53a7130b4b2c165856a1f2ddd661931f81e2699c88c6e5c06eaef9f19880215e5d142c3d5a58142dd31debc7bc183437b2f5a68", + "l10n\/he.json": "95565877d42fe0497deabd94fd1a64bb5b48ba9428f24074b89522e595bfa3932458a6f6a38e883339e255a6622d56c000bcffc7832a0d0642cdf8158224ea05", + "l10n\/hi.js": "a986c52af4ba78092ef8b5726b1a270c1195819c830e84853cfe5d8680c28c84987c34fca1d10901b4e7c74f99b1f12c9f5f45fee0dcb5169d3cb894812eb423", + "l10n\/hi.json": "bc9d722b0d556f763890ffe8f38b0b1e1287c52ca886425bbcdff216503d9b7d539a58f1be906d5185461bdb4e565103d7aa5e675dfe438853ac8e9e15d002aa", + "l10n\/hr.js": "746c8e816eefba860746a31a1494c50b725aef9303a557266aa1a934dd323aa92612f89088c41dbec93a9d13db3c48b6ab70bac4d3b46177de6499e31966f19b", + "l10n\/hr.json": "d73a821c7efd35a363b374a525c1ed087ced68e8ec443cba8c4d43f72f1535f7873364fcab05595d5de935b1d2a8858f96656cc52a96b48491ff43b1b9586f31", + "l10n\/hu.js": "f4b2bbeacd631a6fcda3b149d4725f6cb585076e383edb6a011399c29b98800096ded6126096c77235053755f11ffd619b6ddd9fab62516f6c0d74d9b2a7c635", + "l10n\/hu.json": "e2af504727210cf5913a74e56647e4dd481ef39a638723edc589d2570007ce3aa0e2c2ef4d9a36a381f772fed5a312f693f6bc562c797d46e68e69719f76c21f", + "l10n\/hu_HU.js": "b9ec1d91df19c6849d210db68bebbec62420013fb3a236eb77403b166d734e880ffcdc55cfaa2b66996c7ae80941dc6cee55dc9b5c9ae673c564ef4b0ff70505", + "l10n\/hu_HU.json": "797c57e3aa71262fbf4b8ae38f87805307edf0e8f1e7755647fbbc2a3db93ae5046c9a85ffdf8df3df88291206d509350fb19a4b45dcaadf711cac25c8a24244", + "l10n\/hy.js": "28be9adaa7b7dd2164c563f9aab7b744a3ad6b57f05837ed8f847e8e9d7f9181fd0d06461a9cc6a26877bb605e5241041475ecd733082d775dfe45aa385ed29b", + "l10n\/hy.json": "804c07cc49b22c1deb07890fd2036b371edbe4a0751849f185c3fde9cf01c6ec8998e7ee3d9ea7ce0892621d0161bbcd5aae85b5e287ac26145858c58e0c468a", + "l10n\/ia.js": "488245a1d513c7f2bc563d5c67b0db4f5ab7ba88cb67964fb513648c2e100a2581f95ae4c9eb2bd143d470d65c962eb15e0a3775dfe212edf258aaa49efacd37", + "l10n\/ia.json": "618133a3b6d8df8e9993eae72ff07405b1639f25754708958fb43ddd9a36a4c0868fdc539b3e2c41b2b9fac5cf187279a9e6d21fe7461ed1f39f7b21a98d89c0", + "l10n\/id.js": "51e612a4ed2a03ec3cb7153fe0334f18b898061313741e8882bc8e89ecd0c502d781eb02fd96b8840c39bb9ec04186122576aae8aa7e0357299c62306806f012", + "l10n\/id.json": "9f1382816d3c71eed55aba0461c4050fabfdad40b3d6303ba397bf6a18144845ffeaa8bd580fedbb9fa4f77ec67b2ba15fa29a9b2ea34ac5ad58092889b4dba1", + "l10n\/io.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/io.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/is.js": "e729f05c90ce0874a92e3dfe5cefd13ee950b70fb1ba1b13af04b3f3f9900e850eb7d6c7ca7705ba4d30c3e6495ba11d2a19cf8040ec86ff471c940790cbe254", + "l10n\/is.json": "4dc220104711dfe63a9309ce576133bf186e1f64cb9e2cf46c6f18431c2f60a6ccc78a0eeccdfbd5dde7fbde78790ba14867fbfe38d46881e496180d596022bf", + "l10n\/it.js": "d520831396d8a3294379d286d67e1dcd7b02f97dfc4389c96291810ae7bef278bcc4fb53471768e4d17953f856b0bb0eb478b75d81a7d3f44dcd81ffc65ff518", + "l10n\/it.json": "66be379ab6eef655fce00f77f30bd378da4067960fff7b0f959289035be38fe4d1baf97680eeae0fbe73fa780cf4a5d4a76c975a7cffeff8b78e7f901dca91f0", + "l10n\/ja.js": "0f7a9a7c60392be208a4d20580005027e5362e0498137080540b31db8a871dd660584382287586d3906c696ee852b56c7d1e9d847b32c9aa1eba1f0bb04d9cae", + "l10n\/ja.json": "3840073b1962995677730ff1a6a411f7e636161803a40474d0bf7af9e8a4148feaf0b2a5c4adafca2ce226f6d343312b9979bf220804a56903e85517d3f9b521", + "l10n\/jv.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/jv.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/ka_GE.js": "b06bf83267a8e77fb19a9cc4d5d6b8af2a664c791bffbf9a7df7c02088573e5f3f6a67b9050aa33d765833dbb7ef62ef6bb0b83d0db1886e48ca897a196de708", + "l10n\/ka_GE.json": "c3efcc5455e3769bd704db9aa3ac7452f31790ee13d66faa81392366fe633044c3543d79fd8bc57bfe15112167211b0eafeb5d30584311b6fb6a7408b4b17c68", + "l10n\/km.js": "557c1bf0bd7219d7de10270639e674884d1ad088ddbf1d69a149e983b31588285dfac7ef1bbcc345d0093a01b1fedd2bae61bd99a2a407060f6d2b718adca2c2", + "l10n\/km.json": "0c4181d193c2900bc6cd2c11ac8b3550fafea4b9d9771bcead54cc31fb7e9686e890ad6c1cb9013f3b46a273669b5fb79b66472a89735efbb6599ff48c347e09", + "l10n\/kn.js": "8ea32b354ad6fafa8163c4e0fd71535d00da8f5e1a9e043c7a1aac4694581a4013b75e6e6aec3c68f365073f82096ba2e1690c342647dfaca56de30d1e515074", + "l10n\/kn.json": "095e1dc0efd11fc03456fcbdcddb933ab2d35a34f6e80b6398106b68ca46545c23fda045c7c70a1ef5882b48f17fae5936253ae81fdb39af89e7c2035a985700", + "l10n\/ko.js": "060326aeea20bdbe45809ff632f47a984f07e634c92186841c182e924bef170a4a2f0ca97f9e14452b9736d9faf73323ccb1400a4506fdb0798bceb8443c0114", + "l10n\/ko.json": "02daf105d3a8c34aeaae8607e6650d97a7a509652e6c8d7ade48d5e920a1d13e04920388d1976b399dfadbcf4e54eaa94c2d226d29826914e130e975a50c49bb", + "l10n\/ku_IQ.js": "0dfec555d8a4b44beaf255742023ce82505773094d0557ab15c713713563e83471af7820a94b32609a097d20b5be01852a4a7f957a3526ec2fed392246765ad2", + "l10n\/ku_IQ.json": "d77052bc951b1c1402ee001854f5fcf9d649f35f991a134828a8967e46298aaa673fec136f53eb0eb979852fab170ee851cca18d7bd9c641567a6cd1512082eb", + "l10n\/lb.js": "75cf77133674b06ade17f149ec45e56d8a8545df01d4a796a0b34a8f2d0302c97437d4e5bcb4b70626aa520cad2a11cc25c37848da80bef9d64489c236952c08", + "l10n\/lb.json": "1a907088abe0a783f2eb4dfafbf6ea0ef51ae606fe2fde9cbfa52b409db859fbddb35d45afeaf16260367dd59978fee5ba76c76bd463b5a3f535131fbb161dd3", + "l10n\/lo.js": "71e16eb185207be77e8efa486734ae0f4c5e639cdbdd799d9a0f1c59e966d0c0877c10f872a99a4d0489a2b32ffc76efdd09629f6b587f57e5d18582392b956f", + "l10n\/lo.json": "8feb98b74cc4e22fc60b147fbfe34148b407e37ea50e74cc8b205226a3db47d592ffb1125eced07fbebe9078f961f85df3ff6c33744082a7cc9a59db9ad9269b", + "l10n\/lt_LT.js": "c87abfaed4b16e87d8479a8857b53a0cfbedb7ce0359745189b6768e45214bbfbd9898c10121fae7d0dbe74330ec53b7b66268e00b250e947a14608969005725", + "l10n\/lt_LT.json": "bc65eb3930ba3115de9248f124bf83f5cab0d0daa2aa009cbc2c4e639f7107ff51cfc6f97ee52943ce4e10402a5654efd0ec3ef666d636e7474c3ed4d9f93958", + "l10n\/lv.js": "578d55d2ffca3df7bcf6bf822dc53d01a413cd3254e7becc3f6c99983fdf97376912b46ab1302f7ff4c4806b9e43b5a68fe51ee9d188eb1aeac3cd5cc12b9f1a", + "l10n\/lv.json": "3d79ba3206f961b53ccf35653af394c292d2d22df3fe7d670f07aba765c844291d932196514a49c0d607d3ac19a57ad7e52be7df86794932e5e71849ad07438a", + "l10n\/mg.js": "584616c60777f992280413b3849fd779c5f8e1b4da2f4cbd3864dc35842550e01076fad35a6f95ebed4f32436db05e70f613e95e676a83add0e36232b922a0f8", + "l10n\/mg.json": "f3711573f0f71802cb423dd9c506c602996a7fbaab151df96a39f5049ef4f15617fc771d71766cca8f22e50ce5c5319f4438add093fdd0a1b73c5344d8c34348", + "l10n\/mk.js": "e1de68cd6ab6ee18ca877c29472b3d51670e5d531a92f8c6c1f6b586a4dd7b275a609edf766a8bdf1ea1ba26f15d26b29e3e6c7fd701a6c04b43fbdf4ff0de07", + "l10n\/mk.json": "c6142a36b4d70caf5775a80e9bb11b9f2f8afe6d71879f96fea1712e80e6cfc9c2df993b2a1c6a0f00971e8b022e4157335ad5d298d0d0b09a4dc9e5d114a069", + "l10n\/ml.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/ml.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/ml_IN.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/ml_IN.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/mn.js": "0e2c26e565a2ae53ede2163b5bbc8972a5f1064f98d17acab0fa68238289c342026166679a2a1019b643006f2c8daae22a4f27ffed82dfd74bcd65a54fcf4e55", + "l10n\/mn.json": "180297b8d0dfb8cabbaf576adfe452df26fee9fca88f33f63a1af964cee633ab6170ef33346f91991b42930603a44b3b6a75bf611c0d0a44c6948ad77409a60c", + "l10n\/mr.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/mr.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/ms_MY.js": "7733fc4a26e810877d77382d7ebeae209c8f1aa5f72f5528345f9daee2b7cbfa7f2e930a5a5f5a1ee8bf024fe3ce2556313cfd53a2788ae5553a4ae9ae51288f", + "l10n\/ms_MY.json": "3496e34b48fb8957469211e293f49cccf6301fd77206b8febf0873e009d1bd32ff512fc10d9ccaf8e16691965226788be7e1f1726e33f84cde735431332bf5e7", + "l10n\/mt_MT.js": "9e61dfcffa861ae96f054fe045d24544ad45ead40a56e25510d1442c254b89558b27f687f1c1dcd47e6e5e246446c8cc18b2e95401a4641f5e1a566c438ab7db", + "l10n\/mt_MT.json": "416cc992378a978622e5be64c58e6574a0afd3b667f43b878511070f0d30e99c98796438a51b2262ff3d711d6c058f16f917e43e5629d9f825807abb04896109", + "l10n\/my_MM.js": "d8a64fcc6e0ebd6d6bdcb2bf14536ae752aeca9959af92c91a0f15da677ac6fa14e5950d95959e14181c13a21bc8cf531543c2162430aa0f1620f2fece60bed3", + "l10n\/my_MM.json": "10d5f0de5741ae2bf6b9d57459a604b4d495f48ec29546cc0989435d6b2c3a63cb921678146889ad8499008a7e6afcf397b2260aa7f4c2719b74a2fed8ed5c16", + "l10n\/nb.js": "b494829a82fdbffa2aed72e48815ad12f558201251dab036ae320d75b963754b0d68d856649d9ac91d38003571aadb3865396582b0593e4c9b38d9f1ecbefbdf", + "l10n\/nb.json": "a1f2c8423b57f69a9ade086cd264d7427c482e7a8f9f01d9e89244b2af96950e393c67325d833157c718c9e9d039b0903083abec580ed77cf6c45e255250ab88", + "l10n\/nb_NO.js": "c189ffc496d2e9caa2553dcc01d265270759683281d2db99a7aa90b1ddf37d16c7b08d9eea5aaaf5374a1c0ec8ed75eda849d3167f6b6b88bf2dcfd6e68515f0", + "l10n\/nb_NO.json": "55bd15f5b8c45de595c5f63ca9d84c914136b98e7ca687e5aa4239312ee83dca90a0824c534a0a6ba6e41d86b8d9ddcf4a7cc5adba0d8e675d2c9a0922c63abd", + "l10n\/nds.js": "347919a68917071a98fd893c6ed9828882c96630d435fca139d39d0915dde217b477f810f2ed0430fe9d128e4ad5269c24e7843836069d585f8d8846e95ec06d", + "l10n\/nds.json": "2745b67d31fed43d75b93518d5e0c19e953f29ff347f8c368579ab81e2f297c3e60ea3ead89c5bca323841b18a92ed50e5388539c672ea3e6aae9ca01bb70009", + "l10n\/nl.js": "d6115c34851e7439172de55f70f7c5de3d501a48caccfe4d134ec3cfa44b06cfeb710f20faaa3bcb5576cc3f201fd5532f3b4d56ceab0c106ab97dfb1e70a73b", + "l10n\/nl.json": "ee24d1345f02f3a1c752d0e6150e9ac977cc32d90781f45793adf647c86fb4b5b397f794e645c2ae5b54b56a11322db8626b69e8f74c6ff5d6030feb2fb5d5d6", + "l10n\/nn_NO.js": "e6b991393137b4009cee5b5c6d4f98d992a1d1b3ba0293fe2ebaedc1f5c0bcf0f81bee58414926968931f1fd1180afb4166c32c8a389ddc217801f3223270db3", + "l10n\/nn_NO.json": "d4d39a7c9fde982c00d82b19380a88d27ddc556e812a2f1cc2b79272d0015d0a00e0fddce7acc875ef395ab1ca7a6b30d041d517e5ef96d05bf4de687b232697", + "l10n\/nqo.js": "71e16eb185207be77e8efa486734ae0f4c5e639cdbdd799d9a0f1c59e966d0c0877c10f872a99a4d0489a2b32ffc76efdd09629f6b587f57e5d18582392b956f", + "l10n\/nqo.json": "8feb98b74cc4e22fc60b147fbfe34148b407e37ea50e74cc8b205226a3db47d592ffb1125eced07fbebe9078f961f85df3ff6c33744082a7cc9a59db9ad9269b", + "l10n\/oc.js": "b5fb2a9e49b2eba4db7004143f53eb07dabb551aa7ba540bcf842825903a968945cba7140a643b76b6156c4e9a2055c995675e3103a0d7995b7a79f0ac6884ec", + "l10n\/oc.json": "c1ca15652799fa8c90aedd61811283edc658967141a342551d7851e184ba1d879bd400b9b7c2ee5ad9e24d1ddc5982bb20e4eec8d9365b1814f86cb9aa3911a3", + "l10n\/pa.js": "e400b8463e8d8976d564954dfc806ce69c863e7ac4d57967d190980db7db00f9ab2fc6c3e700d6968af41153c7b913f1517b1d29e1e42c323b6db00f8959091a", + "l10n\/pa.json": "42d8c05216a31f2fdaa6a0bed84275b3cc72577867f572768b500d7c53089f790a7c95ebcdaf7ec069b839edc82c62c09cab8f034cd989ef32a3f112cebe0af7", + "l10n\/pl.js": "f68fe730e56851a76cf2784fba74b102e17c041e1a940b5780388950045f67c46bd6ed23cf307385b1eedec413a824f0ede52b07cfdd33a62fd9828f932b2276", + "l10n\/pl.json": "2436db571356192298bff919876091e6f75cc53bcee1aca4a0827464e84a41941e696a5ebe6daa960d0b4fce29f521151545d5e2a23207fe18c2b4fc2629f407", + "l10n\/pt_BR.js": "c639fae77b0becb6f5b75e28fc428b0690d608b7732d3da8ed1ff6f6d25872630097d0c692f39f4a2396d884abcedf0931f0788437f7978bb0074fd6a7e99e4d", + "l10n\/pt_BR.json": "aee319064a407b5a5c91e33b3ea9d1d5a80fa733593b653194bf75ab38946bba7ae739e640a8fb0d1a719561f8733c1c98d5e8d67ad80977d73850dc76af72a4", + "l10n\/pt_PT.js": "4f978fb2d2388ac0aae46604cb0ecd7ff9b6ccfcd2ba46c9ceaf460bbe288b086102440519ed0bf26f4627e06b40d1c834adf83d1800905c2af0fac76d009dcb", + "l10n\/pt_PT.json": "e3d687259fe5ef5b271500bbbb0b703a45273b08b82217e043322cae0b2117ce930f1494d964ca9f374ac3507461faa1816297cace5a68e192e144ef5ae4bdfa", + "l10n\/ro.js": "3c4ec1135b96911d7d9afe58813b9fa7d2ed3719418089f2765b09f53235e519abc4efcedb691d4dabc9f4a3eb7960816ba4041e10fa679ea13cd7ca0068c586", + "l10n\/ro.json": "e0c6da762d72a55795773ae6047b1f3eea1e571a763fa44a08840d2a94a8f5c03dcadc5c350aeb6da193b3a6f3b4492554eddceb3f42de5cba671a947810908e", + "l10n\/ru.js": "cdd14593f983e84518c632c56a1291da1abd0e29c3e7186b3466ff9dde6dcf688d6473683ea7425488496a2f59c88a599f19a7e389e6c2134de7b3e8377fc130", + "l10n\/ru.json": "bf852975fb4f892eebc8c1dd29f61adde906acb770ca53df748a26fe6ca80aa6cc8a9b6ffc296f38dbf60bf79f0156a015174015da1c1b978f7c5404490e2035", + "l10n\/sc.js": "5e0790cd357fcb3b6f6470e37cf5ceb5fd475b28b8a4e69b1510d3ee4e869257ec2948df5ac9d632eda947b57fd18b2730152478beab0c320d9a8b9b2321c08e", + "l10n\/sc.json": "99ad09a4d95f6149e104aa45e53e66c4ff780c0d8a09efd3c2c1139f145a86802fa1dca1d7bc47b702be3dc8fb2da91a267e050326ffdf93a32452c412d3b9a5", + "l10n\/si_LK.js": "11d7e8a10091ff41295012b8e6fb92c61e68c798f39c5373f8bc0706088d30abd2d4d1f164a4704a9be0f8e8896bb051cbd2dbf120bb0a97b1aee26704eacb5c", + "l10n\/si_LK.json": "4289d93cab4bdbfb29b296a41f568d4d60b57ccebee1d3fcc443a2de7cf7a65dd42a1f08beb4f392598337d7298402e6b40a79d6e2cd0cdfb78bd6499e4b5e76", + "l10n\/sk.js": "5ca8ca4e5ee189a7a76045b278534d6464978a117f45012081862e59d0c210ba091b9d4d3978c5c11cc721b009eb79711c6002e14f0f7ab3dac76a7a6293aebd", + "l10n\/sk.json": "1f7066ca215833b8469af446bb95e4a4e3b55c7dff26b72b404941869a0fe45b871a4256ea99b2110f0f3de2fd3eabde509e86c64eb25b5b31f698ad098e5592", + "l10n\/sk_SK.js": "bb5ccd8a5ab98632189293f77a0118a404b04c40d80d6e706ec4cae42400fe4bdc64b7190e43838f7e652265683d630c214859c2df13e7f0fac5c72ab12aa11f", + "l10n\/sk_SK.json": "baf68108f6b8f25903da70d8d0402a48b0d352da14a7e776d1c6a08970cc375d1b5ab0f5a0b25cd79d78b247bc99f4343db3a2075939be52f2a44b3f74ce3e9b", + "l10n\/sl.js": "ca5134cb47836e077573cd2ae084d032d17c959caa9bb386ce9f892494351c482a4cfe0dcf014b0c7ddba2f88824e5b94067373ce5a2ac316260b65b0e283a25", + "l10n\/sl.json": "07134d7778a39a582fad6a6c8a86f746d367e674f90b56fcd8b526db81a941a4ac6fb31c0cfcae88dca4cb38d97c1d81710a4094500a61f9c7452be7952208ff", + "l10n\/sq.js": "d5d7c9573b1273df378c569ffb2af8bd3c4dd504423e6cb3c822e08db1fe213cc5c7639b45947b586c339ee4b861e17f9ba7ec2b23b156e45874d3966109e17b", + "l10n\/sq.json": "99eeff59b4f779d4716550d6ce4d3ec985159f580d0a0ec74aa27e4963f2d068e011583b3e73aea122afe47886f54392115096d984d13a462914ec38c8e9af17", + "l10n\/sr.js": "8e4aa6886c20f2752c24ababdbce1a29f6e63c76cc3269e23ed3d6306ed7f3893cdde94b5bcee14d483da6ebfa00640f039a074abcad9a2335505c37e69b7f60", + "l10n\/sr.json": "c8a91a20aaaba926efbefd9a4af0287293e42ddc2dc6b44b54185033bd5ff23edf4bf0b9358f197cc7009648527f8192003fd0007cde035179a8aa21a050bd36", + "l10n\/sr@latin.js": "27c449e60967619e4b4000565c772f1dc268f1dc29349df639894b2f8567b1a17451e1c25785d2a727744418775bff0cda80f8639e418c4000fa5530adbe7601", + "l10n\/sr@latin.json": "052896ae8c2ae93b2a5212386172bcf3d20d0e20febb00d26abd519390858788c83599eabe5730075b8056588cffb2868fd4ab15b86e523faf048d2e1b484a38", + "l10n\/su.js": "71e16eb185207be77e8efa486734ae0f4c5e639cdbdd799d9a0f1c59e966d0c0877c10f872a99a4d0489a2b32ffc76efdd09629f6b587f57e5d18582392b956f", + "l10n\/su.json": "8feb98b74cc4e22fc60b147fbfe34148b407e37ea50e74cc8b205226a3db47d592ffb1125eced07fbebe9078f961f85df3ff6c33744082a7cc9a59db9ad9269b", + "l10n\/sv.js": "726af9f00e64e02ae733935812a7d9e16a6d5fbd8190984e91948b64e813c233b65708b3d2e7e3ac2d55e29fead1b0306a6fc60a7ec41fa905c7e217c47f6f73", + "l10n\/sv.json": "2066133c4e7a42fc17e3b41abee63a246003a7131446efc563563fdea90881bdf308d33ffcc21d8ad87a74b0761299c333c79e771f6e7f752f2684839f5300dc", + "l10n\/sw_KE.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/sw_KE.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/ta_IN.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/ta_IN.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/ta_LK.js": "13300e4a5d50120a48e74f0485e7c9daace90aad70dbd10fdfe35431a2b776feec6ab4821900828ea655c8ece207d3c0769d1f346499af725b84d0f102779cf5", + "l10n\/ta_LK.json": "d32cbf9ae21cb9969c5a91f0e10effe033497e92302d2f99a6e7a9e816f6f53eda427730f82e953cc77b62f482b30b882b2ebf72b15e51a624a3674ec4a08d99", + "l10n\/te.js": "46f9a4c2891e920be4269cd6edb465e638c72f836e234d6c0d13dce223a8bdc9166cb28b1e752ff390ed000e489f2b0a3d96288b54f24ab6c23ea0edce037633", + "l10n\/te.json": "45840ca6a54a2fa15af397413b7f814cf7d0b5f9c24baf86988c162b67b73054a552cfae7ae97d8ae0c771d89ba6b157f2c3096d86f367a9529ca0e80539f053", + "l10n\/tg_TJ.js": "2e1675519b2c15d726505516d09fdf613d56907e3bcd3fc31c06dabb13639ab436a0b95879dfa115e53996070264b9b4f2555ff31ba58f89d4082d76a5e5c2b2", + "l10n\/tg_TJ.json": "0229170d1834bb20c391c0a9fd4dfdb43d495f2b9489f5c46ac5a673acc15f474732c222e4e5c79aa6221ab1fcf0ce298ced0b1111cbdc7fc36198dad72ac8c6", + "l10n\/th.js": "968cb2a4687d3cd22d624ee198a3a2b3c7ce131b31cfcd7364f43ae66aae1b48906db6b5cd3e6d208c25f98f0bff1e2726cde89f33224c53bdd08c37f054f3e2", + "l10n\/th.json": "a8600178381ef1ccae069d9dd54017ddba71f1446cccee20ebf8ff4402e8aa1a3df316008e1982aa1c353dcb428492ab1afd0b9f9fbcfba40f6d1bc43e65df0b", + "l10n\/th_TH.js": "ea5a57217458f1613359ac87872d307cef6cb64bf63506d521ae8c9805c0379a5ce7e39da0c9bea35d103489054e30940fd7a91644b54e6e40c8e50e667f549c", + "l10n\/th_TH.json": "ee940b017fffe5e1256db9fccc2b346bd75e1f5f68373285923907f772ebbf835c7b2f96db4077025a2b378c946aeeb564e2706308650be10ae07e527ea24659", + "l10n\/tl_PH.js": "584616c60777f992280413b3849fd779c5f8e1b4da2f4cbd3864dc35842550e01076fad35a6f95ebed4f32436db05e70f613e95e676a83add0e36232b922a0f8", + "l10n\/tl_PH.json": "f3711573f0f71802cb423dd9c506c602996a7fbaab151df96a39f5049ef4f15617fc771d71766cca8f22e50ce5c5319f4438add093fdd0a1b73c5344d8c34348", + "l10n\/tr.js": "6128fc63768ae51c6b079313fd138a056379ac0dbb39a083c30f2c83bd4a87e2d4967ba2b9f6fb1845bcaf59e5bc18d58eaaeb3cf565b08a6de397af11bee5bf", + "l10n\/tr.json": "c0ecf59df4f1fd18f0866875be099d832b5bc3566d5551b444e1088dca8874c1dcaf28b9ce621a82e7688770958f0fea996591831b8281dee3c7df36a75018c2", + "l10n\/tzm.js": "64a3c0d91672049283317be11a85e316b547ca3aaab9849b21f7a09b22d1b0a24b58e522f9b5269e08c1a9e54305c381a4f0ce6a03f0c1aa1706a91c5cb4e11c", + "l10n\/tzm.json": "13ac19c58150750ea44bb764fa75811ebe09f8f98eed65e181928b1944c6c19d3763b05bfd86ab9a31198c0ec58b2d3ef3603bbb3a77ad6be8cf2af356dcd65f", + "l10n\/ug.js": "d3129bb0be6982e1607a37482e595a3fc759b4847bbd804b787124b3822bde529fdb2ccbbda3d128f86242f1af820558c524185e6789ce69f8c24d94078ef961", + "l10n\/ug.json": "971bc6057a1c2f68d462c53741254a96afba92cc44bd53bc02500867f94a39d6d08484ef7b3d87be136b4e2534d0eb6139427edc0aedfe05dcff44cb75e0b36b", + "l10n\/uk.js": "67fbc8aa9dbb8f92e2b8e3fd5b6c052d91a62e676799346d1243092bf65c71411f9954def0ef16dcca05a945b6b5a77788da896d20c883e64e14d86bdca47e18", + "l10n\/uk.json": "2a1870f6a55b18f71733eac9745f45f6b05746cd24b6fcc99968ae2ffeec9a3c5b7d781550231447246b9ff98260248e19ef561511a0e4f9ae56e53b21752806", + "l10n\/ur_PK.js": "4af2df9528ea686197aacafd2dfd8a4d2ad579491418e564ce57a07132c620247e5d3b7026872acd5636a964b24d26e6310f80fcbf09aeb8705e3f7b00f21928", + "l10n\/ur_PK.json": "e7bc6b8ec19eb4eb552ba21f0895846e3856e0c390e6326b1b7dd82ae6ce6f19cced8af35ecb4047ae9d65a57808a72e3d6e5680e2e7a0dac5cd20f6a668423a", + "l10n\/vi.js": "d41c49aa9f19b432c0999ebadffa6add819b0e26de358de4d0651c5fa783155004d9e37c618b7716d5dc40ccf72afa02a856bbfc5ac277aab25d94fd74efcf14", + "l10n\/vi.json": "ce4b9bf4224b880a771c85449a9e72533b7013d2c7af750af5acc28da77e6bbfabec1216f96206f168d109b0a485dd70a2b97d663de44dbb49a29726c3793849", + "l10n\/zh_CN.js": "4e965563a011733ff83977e824cbfdbf3a60f9f487354c994e9a515eb2f4e7e3f8871b5e4a8201f0e81522c4c98b019109fea33584a324610ff8b5e2e1b31b17", + "l10n\/zh_CN.json": "a6c84759910240d5e7ffd2ded4cc880dc5b7d82f12406587391a17e33f290cf6c4c963cae50d6554d6181d0cac87aa741143a37530be8ced1950dcf95a3bcc89", + "l10n\/zh_HK.js": "ff17f778b71dfa55f92bd369da7eadd338fb6cb3a8488ef469faf2c55df19e8b5fbe8dcf4b58cbe379c7baf77376a1207073ec8b7f5c3313aaf45c497b90f03d", + "l10n\/zh_HK.json": "8d1fddfabde1f51b71f6d1714277a24d972a5085053183113eb9c1510f4d885c47ea9fe452a62794ffea2ba85c359b7e176cd5e57b4c905d288121282e66895f", + "l10n\/zh_TW.js": "5f14c275d04a638f15a7001f2549dde94a298fc4742305acaf06c1af61e5df1219dee571dfc748428d318ee3891b7aa1c285cec234af7181cc739f5d6d1d0b6d", + "l10n\/zh_TW.json": "46e7fa57a25dea0ae548f176f7959f00a1d63aa2eb1284bd70cb1874215b547e83fc78c34240b9d4aad0df9804ac2cf43c410a647e3af62746fd6bb32847637e", + "lib\/Access.php": "f7b11f0818fa5d5253fb36cd74346e18ced9a0c37b3f76ca1a1041d319effef9ec231d3b70fd4e58f89c32f5ad101f818c9ed352af05de0cb33c8f83f595bce6", + "lib\/AccessFactory.php": "fed958be87abcc5e65f4ce931fa77581439bbeee19bd4608216b6c3abed355da89bdaa678b0db0b5009c679953b39c49c294e93737ac2849f2fdde6b7d54ef6c", + "lib\/AppInfo\/Application.php": "e7330bfee8a212a8c8d88d2091f02fea8f051de200c5ec54ddc448b12bfff3b8af0b07b4f2b7bffba1975eeb24691d0b4135eba7bc81c5412013df9d5380b255", + "lib\/BackendUtility.php": "ece4949e04c0a86c808a0e8eb57310dc455ff1ce328a63a54ea253822785e279e0136c65054c619c5fe5229be5b37776cb04b33d83712e129830e94939145c60", + "lib\/Command\/CheckUser.php": "1860e745c85c1ed81efd717c1d726a73f1c5c663c77f80678cc8d2194e001ffb9415be45fec168cc8fb80e886236ee96c5cc90a401c4bc8547503ea0c083719e", + "lib\/Command\/CreateEmptyConfig.php": "0f32781a5ce2cbf2d7366eb2a0ac5b2297a067053b4b451c3b72c38d314870b08ce18d52f7de85185aa30b41ae8594059300c95f6fdfa4216ace07011a169ec6", + "lib\/Command\/DeleteConfig.php": "732bafdf5965e52a76c51b2f6f782247c2211a962e6d89987faf469012f092d6e5582d169b88805d105643b8a036af5d1202f71cd161ef1eeeb27aedd019a492", + "lib\/Command\/ResetUser.php": "155625d1739a3770730b8b24e4b242086809134bbd01e98d8b28becce5c93ac453d5de7c7762fa0e38dfde32da08d009db4009102fc23f06711e088ea6db2ad6", + "lib\/Command\/Search.php": "a51e2224a07b7d8e6b7ec4d737282ad87fd1a2a49f5b637d20fa78e9ee1b2476a05a012f41bf7b7b5d1cb7df43a80573ffafec0b4e3681b041ef1b4c30eebc91", + "lib\/Command\/SetConfig.php": "9f4f265862ef4699e899109f12389e89c07921e8048731841e8421fe83b9d98fd9cdfd1f828111740d33cd7e8df0887f349d832c002bd05e56a041ac7d509452", + "lib\/Command\/ShowConfig.php": "2fb6fe87b86d647d7ee0bdaa6ae24e3379ca984061adf691209912a4c876ab672d57897c70224f8975fcef964a3e3d680dab3b9fc444d91fab084abd44b7192f", + "lib\/Command\/ShowRemnants.php": "4127649c38cc74b28fc29f74aa77504913c3db2b1f415c48d9d76145e37acf27e5bfcb2feb8c067ca7131870078c63a08ce0c4e63e6c66ccb680f33beb2960c7", + "lib\/Command\/TestConfig.php": "3ebcda6c52dedceee00ef35175d497537dfad452b5c1dbda7ed19167c1457fa12b41a22ce8fa4d8e199329e8f1e4ddb3e2b1dffabbd812a34040f3587c019b2e", + "lib\/Command\/UpdateUUID.php": "3234b47b8d92f300a7b0aadc4622e2939c0eb20e0f7f1e6b71061381298aae9c6c6041b57ff84f0820c54a6cb14e3640701f62b1b19252685bfe8973e0779b4f", + "lib\/Configuration.php": "62f1c90fec0ac3da2615a4ab29aa99c777f4483402413eda3696638d32ea397a6aff3e843d357c8c75b0f555820f761305ed1f9942a24c9a42c1beb9726db281", + "lib\/Connection.php": "6561803443e738218a3e28e5b960f3599c03572da404703cbe9db52824ff63938db5fc2d6e3c0da5463cd416613596f9ddd51bc2c29a02f88b077831b9bd64a6", + "lib\/ConnectionFactory.php": "e1840769d3f4182f972ee96ddf28868c692596b5cd4ecaee314ee0a1b0916770c1861d7e18260accd1f755a0da680209ffa7638c76659890c50028e5a3ad4d83", + "lib\/Controller\/ConfigAPIController.php": "0839540a40ad86b9b73f58ea2892b5155bf35a7f7e1edcc20f3d199adebad313bd8c774cf9eaa20bbf8bcf18e998827e587682bd9d49d3a3c59b996deb26f144", + "lib\/Controller\/RenewPasswordController.php": "2945e3ac2eac72700c20f673fd05699b09b2c3c3247672aded135d491e6feb0d0843bd13c232eb63d5c79a25436c87b9fdaef3a31d0a37465566ede670a49519", + "lib\/Events\/GroupBackendRegistered.php": "d200667e83f1ef42fd490f9020785fa7ad93112103e48155c567293bce3fffb19ba190af63f512322ea79f8d905ea8ebbdf74e38a49ec1706e4202836541055a", + "lib\/Events\/UserBackendRegistered.php": "f31c3ace2fca15c0fc21f0b6991d3b65aeeec634dd4d046a7d2e8a592f52100d543b0a571484f6b60908ba814698a530ae2c57caff73bae54beb39ec9502370c", + "lib\/Exceptions\/AttributeNotSet.php": "18e6e419beda48951ceb8861c7f6c9c0328ea1eea653c53239d0f39f6961f14e7c30bf45ba8bf9226ad6cd8b6634571f50a74e06af93a741082048087f5e3de5", + "lib\/Exceptions\/ConstraintViolationException.php": "72fd39d5be57c5a48888bf472a0739a0f8d6cd576938e59bf9cd806d8328dae89e336992b2f449c3b034d37d5fc1562a558eded6048f84845925393025438388", + "lib\/Exceptions\/NoMoreResults.php": "ecce4d8d0ed3eac00cd4a2937c80d167f312017f7025325bf87e1bc963f4bdadf002698f4f615b750066dc9684bb958b0ce17622d1970f6da6f999bbd19c56d2", + "lib\/Exceptions\/NotOnLDAP.php": "4d34954246a2c4c76bdd500054d2f26fee87939c80e655da9f7979465e9b13822fa554ce2bf2ed345a6033739aa2a380dcf168bbbcbf2ca316d8ba4e09ad2ba0", + "lib\/FilesystemHelper.php": "a6a14d047a8df84727524d1bfa8e7209f3e12a971c44a26ff2603679b669956ac0e4d8f41f14d5d863db92e767c614f5403ca9548509285d2d04acbc5e36d185", + "lib\/GroupPluginManager.php": "0423c73153dd13faf2d64631faccf4451377f9c3b9fcbaad9cec689bf5b555559ed806c3ca3419a1369bd19534ef1b1370cd5c40e792fcf337f2063822a1e179", + "lib\/Group_LDAP.php": "62312f1063b3bd97f6d3a53b4f55b8b1c51f342123b8830c550798f2afa8e71a157fa86df25e9767dbdec3046f3dde8a6d919beb59ef973d67148a01e7123307", + "lib\/Group_Proxy.php": "def097ae96ee7c14991961071735e005c15d0721d4a4c94dbe7699deb5a64e75eb3a767f0b22a3bcdd17ea186614673bd3fc9fbcbcc39d482f085bfbe943e8cb", + "lib\/Handler\/ExtStorageConfigHandler.php": "ae2f5aa197de97420beb43c51abf4d1bc5bbbc893078bce95c4b65c32b8c5c4f76aaacc756d80ecec51a8744933bb3c573abea125c0f96b72116172c3415725b", + "lib\/Helper.php": "bf6561094b91db5fff8215612b1882bc50a6e04f92c2a4f7e83dc4e04ebc12c4665630c58e08b9c49954e30f6488fb073d25548209d9670eb76050975c7e4b00", + "lib\/IGroupLDAP.php": "c654e34a049c5ef08477b82cb4b169f07842cdc30f11eab967a0a8521429937cfa63a2ed70c4bd24ffbe70bdfee9c536f9e1a6c07627153b7b81db473795dad8", + "lib\/ILDAPGroupPlugin.php": "feafa3ce79a81618d5b618c2a5018a6357df7d584456ac9664b3f8d6607c1c71571d7cc3499ac766519c202a81346021792d695a7d8643d04e87ada4de97eb34", + "lib\/ILDAPUserPlugin.php": "af9d04d6bca0ff2cabc8219badea1b65b3142fa557cf5808d84ad5a79dc26680cee38bcfcca2217aad9c10febe75b2e79e5ef2e3cf29133dad055bafbf3890c8", + "lib\/ILDAPWrapper.php": "ff9784916e0c8da8dc2e655c7e93d25be0ca2086b4ce231b0ec2769f555370d30d0b08158f2c46c5d8542ac42e0b5f7aedfe59d027c1a6cdb9a05244746e6578", + "lib\/IUserLDAP.php": "c507197065791659755e69a1c9ce6d0d8f8e243b53a8409046fb172b270db33c61f0fd760b7e548ca0f2fbf23d747686f05ce95fd2ee59bd3a512a12f90df3ab", + "lib\/Jobs\/CleanUp.php": "9c613ad5793d0718bd0416d1d3e75f0255cf7952499e8197bd06a2d94a44a0072ef8ab98a5317d9af77f77c6f35f3c780de73fdfb25c487d15467a2664987fe9", + "lib\/Jobs\/Sync.php": "ca0aee704feaee001f2f7bc2975d6364c2b689c92fe33c602c36ff342ba9d0d269943cd2ce67c2dd8f47151b4e2c509c546fc9ddd86024143451f608eea5162a", + "lib\/Jobs\/UpdateGroups.php": "61ba97c7618cfbd5988e0b9c8e1ba6cb8051a0300a33a5dc5755c0f81cde183a31579cd862e9db449f371341fe1d51db8d2c1df96a2b2d0851c1790c47d7c181", + "lib\/LDAP.php": "abf403acf12b49b82803b090a0ac951b33585371ef2209d5390fde0c48a3322eadcd6a4f43f4cefe33dec9bc098e2796807f99789819aabb52797f594b4028c4", + "lib\/LDAPProvider.php": "379cb30e51f7e82e181126f582c811527486c539c3cb107295c97ad822c5d27a17535e8e2c819361c2cae99e2e9f52036988829196339286a16a23e0a9719dcf", + "lib\/LDAPProviderFactory.php": "659e3368302fd22a49ae257c446c9bf77235c3df3dd060af2ce5744400bd856bca0743aff29cbbe1b2da35f66d54edcb592646551a042906c2584b4286dc6361", + "lib\/LDAPUtility.php": "eb057d0ef0b5c499fb8235cf2ace9ff3458ea2b1692e093839df2aa6a18a1e62f970fa313bf425d6080e217b27e016d087d8fed51aaa1884baa9cd1aee69e49e", + "lib\/LogWrapper.php": "cf4a777e4f6252e7d754e2c36afeee565dbd8ddc9c467475ef608561509b98344cba416f77e1c78d6f9ab2841ecd38d2d3b51e3d2707cc247b9a66e99b0ca705", + "lib\/Mapping\/AbstractMapping.php": "31061d98f6b9a200740f62c98937ea0b04d35b0522db656fa8005321cb2c22d44727bdade91bdb688079d85ac318fdf0c79250a24788551f66386365816b172b", + "lib\/Mapping\/GroupMapping.php": "fa8e51cdd7f69f39271b0e6e49eaa84bb051a4e4afe1e758454f82273fc328a6bf41f578e8282eb5a906924df6bf973a83a9daaef048bbba27d878842bb7d2e5", + "lib\/Mapping\/UserMapping.php": "4da1e822631d0b80a1a0415a0d64b94ab9e76b304bd1176b5757c90eee1ba95b791a2fd018d5eaa1d59bdd6f2bce596f94aba8642d27e1ed2ed970b3054d6e57", + "lib\/Migration\/GroupMappingMigration.php": "864ec9f8d23d38525ba481f42400ed6a8b5776b11a9627667fc1e35ac56e805c84bda525fdce59d99290e45743214a7e61c6de74c1170f67721ec8bfc0d7589b", + "lib\/Migration\/RemoveRefreshTime.php": "bc3bd50145fb5157466f555ad4782918378a13715e429408992506d3d00da2a5eb6c7d93ed43f8318b55691632864787a049f0038a11b9f7c7d5d49c05df1fb4", + "lib\/Migration\/UUIDFix.php": "f842e8c24a89af8dad67f98a9aafc5dae7e6a818cfd5d7f9cc67976b0ae5833bdfb54d808b8af20e419c427bc39e93e77153e039d6421fd18637e9a80394ad79", + "lib\/Migration\/UUIDFixGroup.php": "cdf941da5e238e0e6d89f05fcce9bc8c9b5779c13c0aa5c46f9fc73ab62882cb349714f03d41f6ddbf9faef443f491c3fcb26fbe49d4ed680159aa59c22c2ef8", + "lib\/Migration\/UUIDFixInsert.php": "998f6b89bbf1dccf9f798a514f66d788e1a387ecb10ff0448b2b07f61d4b8aa5965ceb688769c911926d4aba3649bc2dd5e6b0ccbb2478c8893dd3f5184b5bdc", + "lib\/Migration\/UUIDFixUser.php": "b339f54f7948b730f23aa68c445f68e76a07685c613d25c0a2e03dc59465b05d063115ab4505174d46c92b5773bc8f4395e439f128b36bcc4dbf4e4e86bffffa", + "lib\/Migration\/Version1010Date20200630192842.php": "d4f1ba48d37028dd3f5220113010c8e6bdacbe3b11455098620d2332fd3b7bca1b6b8fca573491f355c4e8eaf5d55dcc42a08ead36b2ccb69daac91162ddb9dc", + "lib\/Migration\/Version1120Date20210917155206.php": "e449c7f9b6ed215d8513c1a1ee835c3634fc46bf5be79f41f8b6f9a861f59f34058897f560463e5ddb717cc93af8b38306ea7a9b45786f259fba18942d2f36ec", + "lib\/Migration\/Version1130Date20211102154716.php": "2f00d2050ed5add785cd0744260f0a84bf12197b2dff6cd6beffcf76ed12a862cd4bcfcbdfa73a25bee1db905b90f1ea5f13365331c9a9463e9bce32773b2e9f", + "lib\/Migration\/Version1130Date20220110154717.php": "661fef74c01bad1877016ebd09932ceaf4bb4d03012b6066249ba3ae4afa8ba4a3f88727a55ddccd9cd1ad516ba10e43a6de2677f9653089335d613709560b44", + "lib\/Migration\/Version1130Date20220110154718.php": "8b3bc67bbe23148cb3a0f9ab1ffccfd6d6e8ed62ffb35119e34263843dd817c7a0fad9bb88e15a1e87a839f5a1239310588c5ac4e05799b5b58f673849df540b", + "lib\/Migration\/Version1130Date20220110154719.php": "2e10d547abd51381e50245e6d0f3687b7b35d8b9a0d37e2e135e63728e4bed4427bf228df96672904661c42dcf2794cb7e476b2d4cc380b054d3303381a4a799", + "lib\/Notification\/Notifier.php": "ae864be078a1d84744ce31c087fe3014ebe7ea77bb0544d44cd8bce6ed96bfbccd0ea34d90bb609d147cc41d60116a6f5aa6284c9553ac2ba496b2fad5169819", + "lib\/PagedResults\/IAdapter.php": "b8d14dc83b72ee3ea1d5faec4fbd389757ae7275e98430235c9334f83a9020480cff7babbbb66f207813a5d591d74c5bbee0c92b0a03d67e7dcba307e9f8ffd1", + "lib\/PagedResults\/Php54.php": "cbdc343d41c46b56d35ada91b217431f8477a4ee129a01e22a4c283452e574620aa892401ea509b685dff9589d73debdb899ff939dacb9b0944da6ff07391ecb", + "lib\/PagedResults\/Php73.php": "0bfbb04a8e6f987cc68f252a343fc7ac2d7729af9b00606959caebb22e8f1e59ccb18992ab3f20182688717f054ab80bc1c05e86ad454221e7a458ac91465092", + "lib\/PagedResults\/TLinkId.php": "1a624b177c9570a6ec65eb8524860b352c9f3fed50529ba875c428b475bc1d572d14b3128370576038efd190587c1407fb8d6890cb54e2d743ce9ed82514ccf5", + "lib\/Proxy.php": "6c330b78a87b370464e6477d3d927bedcf3273605360047b1175704d0073a8ab2297e73ebeda095d272d5828dc7de92ffb1e20847d98039187580faab1d1b06b", + "lib\/Settings\/Admin.php": "9183621719c8a680cd4d59b3629208c02651339d69f7ae01e5a2c94a4f51b97126d89b1db04f6b1a9e3c8454bdc581879bd0b7b56316b3f078628eab50909e2e", + "lib\/Settings\/Section.php": "d10b6c84c99acacd160b1a869d9155eee3d935d8a5340d1d705ca2a692f24fbeb80ce323f1e15e47f5cb196388e74c5fd3e9805aea039612602518504a824be9", + "lib\/User\/DeletedUsersIndex.php": "73dc5264212572e146beb3c3028bc81577d3524e43b0927eb9e4d9aa50f52fa7268e613b0336f3c6c5fcef0bd73019d3a73bd9f60aafe105e25e2774b8320681", + "lib\/User\/Manager.php": "88b440109bb8ecf1eeacf09d3cfe5deafffdb0d489a1bad02553748630282f8ba48bcb44ad9086ad22e2497e58eeda02aad6f6144371ca0a5627da9c98ed2322", + "lib\/User\/OfflineUser.php": "4a50095c305aa1f24af2c98cd882fd801d6d69fcb12d88c13d6f3c72c59f2e7c257e20b1f0c7af6a0658e3f2ca42bbbe19816d38a0f804db6e0ef1534294e492", + "lib\/User\/User.php": "3a9175eb11905321d8bfd0900df11177695dfa15c54288d75694fd7946e76353eca69668a263a5e875c7504eba5ed97ef9bf3f530d58c5f585ae98eb23b1fc08", + "lib\/UserPluginManager.php": "8a9f4605a04a9eeb6d9fc1d5cc0986387fa3f6e0b51d2160fe332cdb1515c776ed17700fec7759d1ca81f1f41bccc82ecc5f505f5aca86b8940ab3406e09df66", + "lib\/User_LDAP.php": "506a3ad516bd9528829491505beb9645f1cbef14002129266706d7c9b90dc43709ab9b67e49a15cc68bef1c99c27a5ed6eecaec344f5993c04dc452086643cb8", + "lib\/User_Proxy.php": "3792bf686a54baf7e43f6a066e172d1336a178e2daa5fce11dc9a716f022f224e65ecac1924cf717fd8dd168bcd7cbc7ef10b3aa5052bd796876040b92dc16c6", + "lib\/Wizard.php": "4dd4bed76ee232274403ed43be2d9ccd98dafb22372e074cd00eee28ef9102de30710a0500bbc2e094b2501b6ee3b73923be893fbfd6f33fae6f38e3c45ebdd5", + "lib\/WizardResult.php": "7acfbd78c5d5c155dbefbd73fb9f7ec0ffcf083d176dc408681600367e5f4d671386cc4eabf20a3f4f25d462c893f8f74992aad2f61cf9c75dc056e039eced6b", + "templates\/part.settingcontrols.php": "06779143ed2405be1010f4383ef40f7130ec8ec5ecb84ca2c4633a7d2b38a59bd2c0c8696b181b63d4d254b4772808e5eea802f857c192b389be4189b7a9e9e7", + "templates\/part.wizard-groupfilter.php": "fd0c2fe34d0e4db938fd9a1955f72a906576ac16d3fedced2cdc3c549d8a7299e093ab1dad9ab419731fe6d4aa9b878d8153c7dc0a050014418ee63150997cfc", + "templates\/part.wizard-loginfilter.php": "ff5ee3ea77bc0b11f1ed0015029574c857872bf86dbf348bde6989597a8dcc1deb0c871c1ba73242688e13107f6002f1d1d2480190ae18c11f3a11931e4918d2", + "templates\/part.wizard-server.php": "9f04e596ca47ea57e54871bfb13b3cc4a6120d2011ffae6c0d300d9f4698427ef0c2d6b89e43a24b954f2603676277da9566d6b0eaca87fc97f47bc4928db5d7", + "templates\/part.wizard-userfilter.php": "cdc24b922c03685ebe9ae5a4e6301831fcd6403eab1cec3c037ba407bcbc6ba3679bfe1380530c6294f127603fb1f8d99746b431a120798f32b307a96b4a4a00", + "templates\/part.wizardcontrols.php": "6f81943c9ecc3b1f5cee936e433d9d8e50a48b5b30de46e4f60c62914415e51cb3edd165b0cfa8eabcab17e262c245c22c5921672c4e10f119725c08b05725fe", + "templates\/renewpassword.php": "ad655ba0756465ceda08e3614b1c29f1c7461c58182fd60e1f36044d77ceed06e8b60d5510e099dcfcdc05540fbc5cb539f756ca38342736a8acd0ae0cf4ec32", + "templates\/settings.php": "aa03548ff192a4018940f022e55d348085a529b77af92f62ccd02fba55014b284c0039fe012714e549e8def86d3b9d6a826eef23413de87df876f22ff156e241", + "vendor\/ui-multiselect\/MIT-LICENSE": "b27f1e9fc12aa2f9fb5cf3db9f24141f158e82770e8a00fe0ac464478ce9803d2db7d3e5257cf6597adf6c2c3a2b28c0adce530f5a72698a754b0a0983bf8c1c", + "vendor\/ui-multiselect\/jquery.multiselect.css": "cb29f588e4aa9f3d460315384940abc481b7121fe18ed56077e8e5608dc4dc01df1083c76871ae7109228a3b1a0c169962fb901bba323d91f2f4e5e2c16dff5e", + "vendor\/ui-multiselect\/src\/jquery.multiselect.js": "8a30cdb626fe10b5a93ad61bd2eeb39c0628ee1bdeb9fc7bb1761a1bb972c9768a23c6a24e613167ccd49b93a50688cefe22001daa9627e89a1055b1d56cf700" + }, + "signature": "dhQQqqGkK9tVsT+5DowZgppLeuzZT7gWoDoo7cMxG+oiflsWxlPClXu54Lh6or2tHK2lzEePz+fsjF3n6u2LmmbDRJ6bR6vKzWu9PZAkQEqW+SZn7VmRNiFYb3pBdVuCLqfBcKkWco2YOed5modGnjiuc7WatIovrY3VoqMERLJgzKUJNurCj1wyuD2zMOiL6IbnR6PpMRVmbw2WYC46DstRHwug0rCx1MmODIcmheQ0nR0VIZ0N+NY\/s1xAJCo\/n+osa0qPcFXqJ\/ba\/PL\/erifiX1I4e+T7lQBoQjf5k9IDeyNtb61AsjxjrWDLtA+c3EulkdrozLEhMSaXHTYDw==", + "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIEojCCA4qgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwezELMAkGA1UEBhMCREUx\r\nGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzEXMBUGA1UECgwOTmV4dGNsb3Vk\r\nIEdtYkgxNjA0BgNVBAMMLU5leHRjbG91ZCBDb2RlIFNpZ25pbmcgSW50ZXJtZWRp\r\nYXRlIEF1dGhvcml0eTAeFw0xNjA2MTIyMTA1MDZaFw00MTA2MDYyMTA1MDZaMGYx\r\nCzAJBgNVBAYTAkRFMRswGQYDVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxEjAQBgNV\r\nBAcMCVN0dXR0Z2FydDEXMBUGA1UECgwOTmV4dGNsb3VkIEdtYkgxDTALBgNVBAMM\r\nBGNvcmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUxcrn2DC892IX\r\n8+dJjZVh9YeHF65n2ha886oeAizOuHBdWBfzqt+GoUYTOjqZF93HZMcwy0P+xyCf\r\nQqak5Ke9dybN06RXUuGP45k9UYBp03qzlUzCDalrkj+Jd30LqcSC1sjRTsfuhc+u\r\nvH1IBuBnf7SMUJUcoEffbmmpAPlEcLHxlUGlGnz0q1e8UFzjbEFj3JucMO4ys35F\r\nqZS4dhvCngQhRW3DaMlQLXEUL9k3kFV+BzlkPzVZEtSmk4HJujFCnZj1vMcjQBg\/\r\nBqq1HCmUB6tulnGcxUzt\/Z\/oSIgnuGyENeke077W3EyryINL7EIyD4Xp7sxLizTM\r\nFCFCjjH1AgMBAAGjggFDMIIBPzAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIG\r\nQDAzBglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRp\r\nZmljYXRlMB0GA1UdDgQWBBQwc1H9AL8pRlW2e5SLCfPPqtqc0DCBpQYDVR0jBIGd\r\nMIGagBRt6m6qqTcsPIktFz79Ru7DnnjtdKF+pHwwejELMAkGA1UEBhMCREUxGzAZ\r\nBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzESMBAGA1UEBwwJU3R1dHRnYXJ0MRcw\r\nFQYDVQQKDA5OZXh0Y2xvdWQgR21iSDEhMB8GA1UEAwwYTmV4dGNsb3VkIFJvb3Qg\r\nQXV0aG9yaXR5ggIQADAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH\r\nAwEwDQYJKoZIhvcNAQELBQADggEBADZ6+HV\/+0NEH3nahTBFxO6nKyR\/VWigACH0\r\nnaV0ecTcoQwDjKDNNFr+4S1WlHdwITlnNabC7v9rZ\/6QvbkrOTuO9fOR6azp1EwW\r\n2pixWqj0Sb9\/dSIVRpSq+jpBE6JAiX44dSR7zoBxRB8DgVO2Afy0s80xEpr5JAzb\r\nNYuPS7M5UHdAv2dr16fDcDIvn+vk92KpNh1NTeZFjBbRVQ9DXrgkRGW34TK8uSLI\r\nYG6jnfJ6eJgTaO431ywWPXNg1mUMaT\/+QBOgB299QVCKQU+lcZWptQt+RdsJUm46\r\nNY\/nARy4Oi4uOe88SuWITj9KhrFmEvrUlgM8FvoXA1ldrR7KiEg=\r\n-----END CERTIFICATE-----" +} \ No newline at end of file diff --git a/apps/user_ldap/l10n/.gitkeep b/apps/user_ldap/l10n/.gitkeep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/apps/user_ldap/lib/Access.php b/apps/user_ldap/lib/Access.php index b96cb25e631bc..ea3176f7a77d6 100644 --- a/apps/user_ldap/lib/Access.php +++ b/apps/user_ldap/lib/Access.php @@ -527,6 +527,11 @@ public function dn2username($fdn, $ldapName = null) { * @throws \Exception */ public function dn2ocname($fdn, $ldapName = null, $isUser = true, &$newlyMapped = null, array $record = null) { + static $intermediates = []; + if (isset($intermediates[($isUser ? 'user-' : 'group-') . $fdn])) { + return false; // is a known intermediate + } + $newlyMapped = false; if ($isUser) { $mapper = $this->getUserMapper(); @@ -562,6 +567,7 @@ public function dn2ocname($fdn, $ldapName = null, $isUser = true, &$newlyMapped $ldapName = $this->readAttribute($fdn, $nameAttribute, $filter); if (!isset($ldapName[0]) || empty($ldapName[0])) { $this->logger->debug('No or empty name for ' . $fdn . ' with filter ' . $filter . '.', ['app' => 'user_ldap']); + $intermediates[($isUser ? 'user-' : 'group-') . $fdn] = true; return false; } $ldapName = $ldapName[0]; diff --git a/apps/user_ldap/lib/Configuration.php b/apps/user_ldap/lib/Configuration.php index 5a7c732ab7b54..835211efaa268 100644 --- a/apps/user_ldap/lib/Configuration.php +++ b/apps/user_ldap/lib/Configuration.php @@ -63,6 +63,8 @@ class Configuration { 'ldapPort' => null, 'ldapBackupHost' => null, 'ldapBackupPort' => null, + 'ldapBackgroundHost' => null, + 'ldapBackgroundPort' => null, 'ldapBase' => null, 'ldapBaseUsers' => null, 'ldapBaseGroups' => null, @@ -437,6 +439,8 @@ public function getDefaults() { 'ldap_port' => '', 'ldap_backup_host' => '', 'ldap_backup_port' => '', + 'ldap_background_host' => '', + 'ldap_background_port' => '', 'ldap_override_main_server' => '', 'ldap_dn' => '', 'ldap_agent_password' => '', @@ -501,6 +505,8 @@ public function getConfigTranslationArray() { 'ldap_port' => 'ldapPort', 'ldap_backup_host' => 'ldapBackupHost', 'ldap_backup_port' => 'ldapBackupPort', + 'ldap_background_host' => 'ldapBackgroundHost', + 'ldap_background_port' => 'ldapBackgroundPort', 'ldap_override_main_server' => 'ldapOverrideMainServer', 'ldap_dn' => 'ldapAgentName', 'ldap_agent_password' => 'ldapAgentPassword', diff --git a/apps/user_ldap/lib/Connection.php b/apps/user_ldap/lib/Connection.php index 63f2296a16723..c48ff2ff97358 100644 --- a/apps/user_ldap/lib/Connection.php +++ b/apps/user_ldap/lib/Connection.php @@ -267,7 +267,7 @@ public function getFromCache($key) { * * @return string */ - public function writeToCache($key, $value) { + public function writeToCache($key, $value, int $ttlOverride = null) { if (!$this->configured) { $this->readConfiguration(); } @@ -278,7 +278,8 @@ public function writeToCache($key, $value) { } $key = $this->getCacheKey($key); $value = base64_encode(json_encode($value)); - $this->cache->set($key, $value, $this->configuration->ldapCacheTTL); + $ttl = $ttlOverride ?? $this->configuration->ldapCacheTTL; + $this->cache->set($key, $value, $ttl); } public function clearCache() { @@ -570,18 +571,32 @@ private function establishConnection() { $isOverrideMainServer = ($this->configuration->ldapOverrideMainServer || $this->getFromCache('overrideMainServer')); - $isBackupHost = (trim($this->configuration->ldapBackupHost) !== ""); + $isBackupHost = (trim($this->configuration->ldapBackupHost) !== "") + && (!\OC::$CLI || !$this->configuration->ldapBackgroundHost); $bindStatus = false; + $mainServerConnectionFailure = false; try { if (!$isOverrideMainServer) { - $this->doConnect($this->configuration->ldapHost, - $this->configuration->ldapPort); + $host = $this->configuration->ldapHost; + $port = $this->configuration->ldapPort; + if (\OC::$CLI && $this->configuration->ldapBackgroundHost) { + $host = $this->configuration->ldapBackgroundHost; + $port = $this->configuration->ldapBackgroundPort; + } + $this->doConnect($host, $port); return $this->bind(); } } catch (ServerNotAvailableException $e) { if (!$isBackupHost) { throw $e; } + $mainServerConnectionFailure = true; + $this->logger->info( + 'Main LDAP not reachable, connecting to backup', + [ + 'app' => 'user_ldap' + ] + ); } //if LDAP server is not reachable, try the Backup (Replica!) Server @@ -592,10 +607,10 @@ private function establishConnection() { $bindStatus = $this->bind(); $error = $this->ldap->isResource($this->ldapConnectionRes) ? $this->ldap->errno($this->ldapConnectionRes) : -1; - if ($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) { + if ($bindStatus && $error === 0 && $mainServerConnectionFailure && !$this->getFromCache('overrideMainServer')) { //when bind to backup server succeeded and failed to main server, - //skip contacting him until next cache refresh - $this->writeToCache('overrideMainServer', true); + //skip contacting it for 15min + $this->writeToCache('overrideMainServer', true, 60 * 15); } } @@ -625,6 +640,10 @@ private function doConnect($host, $port) { throw new ServerNotAvailableException('Could not disable LDAP referrals.'); } + if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_NETWORK_TIMEOUT, 8)) { + throw new ServerNotAvailableException('Could not set network timeout'); + } + if ($this->configuration->ldapTLS) { if (!$this->ldap->startTls($this->ldapConnectionRes)) { throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.'); diff --git a/apps/user_ldap/lib/Group_LDAP.php b/apps/user_ldap/lib/Group_LDAP.php index 8bf13ed90fd63..8b21b9348821f 100644 --- a/apps/user_ldap/lib/Group_LDAP.php +++ b/apps/user_ldap/lib/Group_LDAP.php @@ -57,7 +57,7 @@ class Group_LDAP extends BackendUtility implements GroupInterface, IGroupLDAP, I /** @var string[][] $cachedGroupMembers array of users with gid as key */ protected $cachedGroupMembers; - /** @var string[] $cachedGroupsByMember array of groups with uid as key */ + /** @var string[][] $cachedGroupsByMember array of groups with uid as key */ protected $cachedGroupsByMember; /** @var string[] $cachedNestedGroups array of groups with gid (DN) as key */ protected $cachedNestedGroups; @@ -88,7 +88,7 @@ public function __construct(Access $access, GroupPluginManager $groupPluginManag } /** - * is user in group? + * Check if user is in group * * @param string $uid uid of the user * @param string $gid gid of the group @@ -240,18 +240,21 @@ public function getDynamicGroupMembers(string $dnGroup): array { } /** + * Get group members from dn. + * @psalm-param array $seen List of DN that have already been processed. * @throws ServerNotAvailableException */ private function _groupMembers(string $dnGroup, ?array &$seen = null): array { if ($seen === null) { $seen = []; - // the root entry has to be marked as processed to avoind infinit loops, - // but not included in the results laters on + // the root entry has to be marked as processed to avoid infinite loops, + // but not included in the results later on $excludeFromResult = $dnGroup; } // cache only base groups, otherwise groups get additional unwarranted members $shouldCacheResult = count($seen) === 0; + /** @psalm-var array $rawMemberReads */ static $rawMemberReads = []; // runtime cache for intermediate ldap read results $allMembers = []; @@ -302,10 +305,10 @@ private function _groupMembers(string $dnGroup, ?array &$seen = null): array { $rawMemberReads[$dnGroup] = $members; } if (is_array($members)) { - $fetcher = function ($memberDN) use (&$seen) { + $fetcher = function (string $memberDN) use (&$seen) { return $this->_groupMembers($memberDN, $seen); }; - $allMembers = $this->walkNestedGroups($dnGroup, $fetcher, $members, $seen); + $allMembers = $this->walkNestedGroupsReturnDNs($dnGroup, $fetcher, $members, $seen); } $allMembers += $this->getDynamicGroupMembers($dnGroup); @@ -331,6 +334,7 @@ private function _groupMembers(string $dnGroup, ?array &$seen = null): array { } /** + * @return string[] * @throws ServerNotAvailableException */ private function _getGroupDNsFromMemberOf(string $dn): array { @@ -339,7 +343,7 @@ private function _getGroupDNsFromMemberOf(string $dn): array { return []; } - $fetcher = function ($groupDN) { + $fetcher = function (string $groupDN) { if (isset($this->cachedNestedGroups[$groupDN])) { $nestedGroups = $this->cachedNestedGroups[$groupDN]; } else { @@ -352,50 +356,80 @@ private function _getGroupDNsFromMemberOf(string $dn): array { return $nestedGroups; }; - $groups = $this->walkNestedGroups($dn, $fetcher, $groups); + $groups = $this->walkNestedGroupsReturnDNs($dn, $fetcher, $groups); return $this->filterValidGroups($groups); } - private function walkNestedGroups(string $dn, Closure $fetcher, array $list, array &$seen = []): array { - $nesting = (int)$this->access->connection->ldapNestedGroups; - // depending on the input, we either have a list of DNs or a list of LDAP records - // also, the output expects either DNs or records. Testing the first element should suffice. - $recordMode = is_array($list) && isset($list[0]) && is_array($list[0]) && isset($list[0]['dn'][0]); - - if ($nesting !== 1) { - if ($recordMode) { - // the keys are numeric, but should hold the DN - return array_reduce($list, function ($transformed, $record) use ($dn) { - if ($record['dn'][0] != $dn) { - $transformed[$record['dn'][0]] = $record; - } - return $transformed; - }, []); - } - return $list; - } - + /** + * @psalm-param list}|string> $list + * @psalm-param array $seen List of DN that have already been processed. + * @param Closure(string) $fetcher + */ + private function processListFromWalkingNestedGroups(array &$list, array &$seen, string $dn, Closure $fetcher): void { while ($record = array_shift($list)) { $recordDN = $record['dn'][0] ?? $record; if ($recordDN === $dn || array_key_exists($recordDN, $seen)) { // Prevent loops continue; } - $fetched = $fetcher($record); + + $cacheKey = 'walkNestedGroups_' . $recordDN; + $fetched = $this->access->connection->getFromCache($cacheKey); + if ($fetched === null) { + $fetched = $fetcher($recordDN); + $this->access->connection->writeToCache($cacheKey, $fetched); + } $list = array_merge($list, $fetched); if (!isset($seen[$recordDN]) || is_bool($seen[$recordDN]) && is_array($record)) { $seen[$recordDN] = $record; } } + } + + /** + * @psalm-param list}|string> $list + * @psalm-param array $seen List of DN that have already been processed. + * @param Closure(string) $fetcher + */ + private function walkNestedGroupsReturnDNs(string $dn, Closure $fetcher, array $list, array &$seen = []): array { + $nesting = (int)$this->access->connection->ldapNestedGroups; + + if ($nesting !== 1) { + return $list; + } - // on record mode, filter out intermediate state - return $recordMode ? array_filter($seen, 'is_array') : array_keys($seen); + $this->processListFromWalkingNestedGroups($list, $seen, $dn, $fetcher); + return array_keys($seen); } /** - * translates a gidNumber into an ownCloud internal name + * @psalm-param list}> $list + * @psalm-param array $seen List of DN that have already been processed. + * @return array[] An array of records + * @param Closure(string) $fetcher + */ + private function walkNestedGroupsReturnRecords(string $dn, Closure $fetcher, array $list, array &$seen = []): array { + $nesting = (int)$this->access->connection->ldapNestedGroups; + + if ($nesting !== 1) { + // the keys are numeric, but should hold the DN + return array_reduce($list, function (array $transformed, array $record) use ($dn) { + if ($record['dn'][0] != $dn) { + $transformed[$record['dn'][0]] = $record; + } + return $transformed; + }, []); + } + + $this->processListFromWalkingNestedGroups($list, $seen, $dn, $fetcher); + // filter out intermediate state + return array_filter($seen, 'is_array'); + } + + /** + * Translates a gidNumber into the Nextcloud internal name. * - * @return string|bool + * @return string|false The nextcloud internal name. * @throws Exception * @throws ServerNotAvailableException */ @@ -416,10 +450,11 @@ public function gidNumber2Name(string $gid, string $dn) { } /** + * @return ?string The name of the group * @throws ServerNotAvailableException * @throws Exception */ - private function getNameOfGroup(string $filter, string $cacheKey) { + private function getNameOfGroup(string $filter, string $cacheKey): ?string { $result = $this->access->searchGroups($filter, ['dn'], 1); if (empty($result)) { $this->access->connection->writeToCache($cacheKey, false); @@ -438,9 +473,7 @@ private function getNameOfGroup(string $filter, string $cacheKey) { } /** - * returns the entry's gidNumber - * - * @return string|bool + * @return string|bool The entry's gidNumber * @throws ServerNotAvailableException */ private function getEntryGidNumber(string $dn, string $attribute) { @@ -452,7 +485,7 @@ private function getEntryGidNumber(string $dn, string $attribute) { } /** - * @return string|bool + * @return string|bool The group's gidNumber * @throws ServerNotAvailableException */ public function getGroupGidNumber(string $dn) { @@ -460,9 +493,7 @@ public function getGroupGidNumber(string $dn) { } /** - * returns the user's gidNumber - * - * @return string|bool + * @return string|bool The user's gidNumber * @throws ServerNotAvailableException */ public function getUserGidNumber(string $dn) { @@ -497,8 +528,7 @@ private function prepareFilterForUsersHasGidNumber(string $groupDN, string $sear } /** - * returns a list of users that have the given group as gid number - * + * @return array A list of users that have the given group as gid number * @throws ServerNotAvailableException */ public function getUsersInGidNumber( @@ -525,7 +555,7 @@ public function getUsersInGidNumber( /** * @throws ServerNotAvailableException - * @return bool + * @return false|string */ public function getUserGroupByGid(string $dn) { $groupID = $this->getUserGidNumber($dn); @@ -540,9 +570,9 @@ public function getUserGroupByGid(string $dn) { } /** - * translates a primary group ID into an Nextcloud internal name + * Translates a primary group ID into an Nextcloud internal name * - * @return string|bool + * @return string|false * @throws Exception * @throws ServerNotAvailableException */ @@ -567,9 +597,7 @@ public function primaryGroupID2Name(string $gid, string $dn) { } /** - * returns the entry's primary group ID - * - * @return string|bool + * @return string|false The entry's group Id * @throws ServerNotAvailableException */ private function getEntryGroupID(string $dn, string $attribute) { @@ -581,7 +609,7 @@ private function getEntryGroupID(string $dn, string $attribute) { } /** - * @return string|bool + * @return string|false The entry's primary group Id * @throws ServerNotAvailableException */ public function getGroupPrimaryGroupID(string $dn) { @@ -589,7 +617,7 @@ public function getGroupPrimaryGroupID(string $dn) { } /** - * @return string|bool + * @return string|false * @throws ServerNotAvailableException */ public function getUserPrimaryGroupIDs(string $dn) { @@ -669,7 +697,7 @@ public function countUsersInPrimaryGroup( } /** - * @return string|bool + * @return string|false * @throws ServerNotAvailableException */ public function getUserPrimaryGroup(string $dn) { @@ -848,6 +876,9 @@ private function getGroupsByMember(string $dn, array &$seen = null): array { // avoid loops return []; } + if ($this->cachedGroupsByMember[$dn]) { + return $this->cachedGroupsByMember[$dn]; + } $allGroups = []; $seen[$dn] = true; $filter = $this->access->connection->ldapGroupMemberAssocAttr . '=' . $dn; @@ -865,10 +896,7 @@ private function getGroupsByMember(string $dn, array &$seen = null): array { $groups = $this->access->fetchListOfGroups($filter, [strtolower($this->access->connection->ldapGroupMemberAssocAttr), $this->access->connection->ldapGroupDisplayName, 'dn']); if (is_array($groups)) { - $fetcher = function ($dn) use (&$seen) { - if (is_array($dn) && isset($dn['dn'][0])) { - $dn = $dn['dn'][0]; - } + $fetcher = function (string $dn) use (&$seen) { return $this->getGroupsByMember($dn, $seen); }; @@ -876,10 +904,12 @@ private function getGroupsByMember(string $dn, array &$seen = null): array { $dn = ""; } - $allGroups = $this->walkNestedGroups($dn, $fetcher, $groups, $seen); + $allGroups = $this->walkNestedGroupsReturnRecords($dn, $fetcher, $groups, $seen); } $visibleGroups = $this->filterValidGroups($allGroups); - return array_intersect_key($allGroups, $visibleGroups); + $effectiveGroups = array_intersect_key($allGroups, $visibleGroups); + $this->cachedGroupsByMember[$dn] = $effectiveGroups; + return $effectiveGroups; } /** @@ -921,7 +951,7 @@ public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) { $groupDN = $this->access->groupname2dn($gid); if (!$groupDN) { - // group couldn't be found, return empty resultset + // group couldn't be found, return empty result-set $this->access->connection->writeToCache($cacheKey, []); return []; } @@ -1185,7 +1215,11 @@ protected function filterValidGroups(array $listOfGroups): array { $validGroupDNs = []; foreach ($listOfGroups as $key => $item) { $dn = is_string($item) ? $item : $item['dn'][0]; - $gid = $this->access->dn2groupname($dn); + if (is_array($item) && !isset($item[$this->access->connection->ldapGroupDisplayName][0])) { + continue; + } + $name = $item[$this->access->connection->ldapGroupDisplayName][0] ?? null; + $gid = $this->access->dn2groupname($dn, $name); if (!$gid) { continue; } @@ -1352,10 +1386,11 @@ public function getDisplayName(string $gid): string { if ($displayName && (count($displayName) > 0)) { $displayName = $displayName[0]; - $this->access->connection->writeToCache($cacheKey, $displayName); - return $displayName; + } else { + $displayName = ''; } - return ''; + $this->access->connection->writeToCache($cacheKey, $displayName); + return $displayName; } } diff --git a/apps/user_ldap/lib/Wizard.php b/apps/user_ldap/lib/Wizard.php index 67a130555f2e9..90c9e9c4323fd 100644 --- a/apps/user_ldap/lib/Wizard.php +++ b/apps/user_ldap/lib/Wizard.php @@ -886,7 +886,7 @@ private function testMemberOf() { throw new \Exception('Could not connect to LDAP'); } $result = $this->access->countUsers('memberOf=*', ['memberOf'], 1); - if (is_int($result) && $result > 0) { + if (is_int($result) && $result > 0) { return true; } return false; diff --git a/apps/user_ldap/tests/.htaccess b/apps/user_ldap/tests/.htaccess deleted file mode 100755 index 6fde30e763a60..0000000000000 --- a/apps/user_ldap/tests/.htaccess +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by ownCloud on 2015-06-18 14:16:40 -# line below if for Apache 2.4 - -Require all denied - - -# line below if for Apache 2.2 - -deny from all -Satisfy All - - -# section for Apache 2.2 and 2.4 - -IndexIgnore * - diff --git a/apps/user_ldap/tests/AccessTest.php b/apps/user_ldap/tests/AccessTest.php deleted file mode 100644 index b97fe321bf70e..0000000000000 --- a/apps/user_ldap/tests/AccessTest.php +++ /dev/null @@ -1,784 +0,0 @@ - - * - * @author Andreas Fischer - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Joas Schilling - * @author Jörn Friedrich Dreyer - * @author Lukas Reschke - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Roger Szabo - * @author root - * @author Thomas Müller - * @author Victor Dubiniuk - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\Exceptions\ConstraintViolationException; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\Helper; -use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\LDAP; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User\Manager; -use OCA\User_LDAP\User\OfflineUser; -use OCA\User_LDAP\User\User; -use OCP\IAvatarManager; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\Image; -use OCP\IUserManager; -use OCP\Notification\IManager as INotificationManager; -use Psr\Log\LoggerInterface; -use Test\TestCase; - -/** - * Class AccessTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class AccessTest extends TestCase { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $userMapper; - /** @var GroupMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $groupMapper; - /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */ - private $connection; - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ - private $ldap; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ - private $userManager; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ - private $helper; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - private $ncUserManager; - /** @var LoggerInterface|MockObject */ - private $logger; - /** @var Access */ - private $access; - - protected function setUp(): void { - $this->connection = $this->createMock(Connection::class); - $this->ldap = $this->createMock(LDAP::class); - $this->userManager = $this->createMock(Manager::class); - $this->helper = $this->createMock(Helper::class); - $this->config = $this->createMock(IConfig::class); - $this->userMapper = $this->createMock(UserMapping::class); - $this->groupMapper = $this->createMock(GroupMapping::class); - $this->ncUserManager = $this->createMock(IUserManager::class); - $this->logger = $this->createMock(LoggerInterface::class); - - $this->access = new Access( - $this->connection, - $this->ldap, - $this->userManager, - $this->helper, - $this->config, - $this->ncUserManager, - $this->logger - ); - $this->access->setUserMapper($this->userMapper); - $this->access->setGroupMapper($this->groupMapper); - } - - private function getConnectorAndLdapMock() { - $lw = $this->createMock(ILDAPWrapper::class); - $connector = $this->getMockBuilder(Connection::class) - ->setConstructorArgs([$lw, null, null]) - ->getMock(); - $um = $this->getMockBuilder(Manager::class) - ->setConstructorArgs([ - $this->createMock(IConfig::class), - $this->createMock(FilesystemHelper::class), - $this->createMock(LogWrapper::class), - $this->createMock(IAvatarManager::class), - $this->createMock(Image::class), - $this->createMock(IDBConnection::class), - $this->createMock(IUserManager::class), - $this->createMock(INotificationManager::class)]) - ->getMock(); - $helper = new Helper(\OC::$server->getConfig()); - - return [$lw, $connector, $um, $helper]; - } - - public function testEscapeFilterPartValidChars() { - $input = 'okay'; - $this->assertTrue($input === $this->access->escapeFilterPart($input)); - } - - public function testEscapeFilterPartEscapeWildcard() { - $input = '*'; - $expected = '\\\\*'; - $this->assertTrue($expected === $this->access->escapeFilterPart($input)); - } - - public function testEscapeFilterPartEscapeWildcard2() { - $input = 'foo*bar'; - $expected = 'foo\\\\*bar'; - $this->assertTrue($expected === $this->access->escapeFilterPart($input)); - } - - /** - * @dataProvider convertSID2StrSuccessData - * @param array $sidArray - * @param $sidExpected - */ - public function testConvertSID2StrSuccess(array $sidArray, $sidExpected) { - $sidBinary = implode('', $sidArray); - $this->assertSame($sidExpected, $this->access->convertSID2Str($sidBinary)); - } - - public function convertSID2StrSuccessData() { - return [ - [ - [ - "\x01", - "\x04", - "\x00\x00\x00\x00\x00\x05", - "\x15\x00\x00\x00", - "\xa6\x81\xe5\x0e", - "\x4d\x6c\x6c\x2b", - "\xca\x32\x05\x5f", - ], - 'S-1-5-21-249921958-728525901-1594176202', - ], - [ - [ - "\x01", - "\x02", - "\xFF\xFF\xFF\xFF\xFF\xFF", - "\xFF\xFF\xFF\xFF", - "\xFF\xFF\xFF\xFF", - ], - 'S-1-281474976710655-4294967295-4294967295', - ], - ]; - } - - public function testConvertSID2StrInputError() { - $sidIllegal = 'foobar'; - $sidExpected = ''; - - $this->assertSame($sidExpected, $this->access->convertSID2Str($sidIllegal)); - } - - public function testGetDomainDNFromDNSuccess() { - $inputDN = 'uid=zaphod,cn=foobar,dc=my,dc=server,dc=com'; - $domainDN = 'dc=my,dc=server,dc=com'; - - $this->ldap->expects($this->once()) - ->method('explodeDN') - ->with($inputDN, 0) - ->willReturn(explode(',', $inputDN)); - - $this->assertSame($domainDN, $this->access->getDomainDNFromDN($inputDN)); - } - - public function testGetDomainDNFromDNError() { - $inputDN = 'foobar'; - $expected = ''; - - $this->ldap->expects($this->once()) - ->method('explodeDN') - ->with($inputDN, 0) - ->willReturn(false); - - $this->assertSame($expected, $this->access->getDomainDNFromDN($inputDN)); - } - - public function dnInputDataProvider() { - return [[ - [ - 'input' => 'foo=bar,bar=foo,dc=foobar', - 'interResult' => [ - 'count' => 3, - 0 => 'foo=bar', - 1 => 'bar=foo', - 2 => 'dc=foobar' - ], - 'expectedResult' => true - ], - [ - 'input' => 'foobarbarfoodcfoobar', - 'interResult' => false, - 'expectedResult' => false - ] - ]]; - } - - /** - * @dataProvider dnInputDataProvider - * @param array $case - */ - public function testStringResemblesDN($case) { - list($lw, $con, $um, $helper) = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ - $config = $this->createMock(IConfig::class); - $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger); - - $lw->expects($this->exactly(1)) - ->method('explodeDN') - ->willReturnCallback(function ($dn) use ($case) { - if ($dn === $case['input']) { - return $case['interResult']; - } - return null; - }); - - $this->assertSame($case['expectedResult'], $access->stringResemblesDN($case['input'])); - } - - /** - * @dataProvider dnInputDataProvider - * @param $case - */ - public function testStringResemblesDNLDAPmod($case) { - list(, $con, $um, $helper) = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ - $config = $this->createMock(IConfig::class); - $lw = new LDAP(); - $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger); - - if (!function_exists('ldap_explode_dn')) { - $this->markTestSkipped('LDAP Module not available'); - } - - $this->assertSame($case['expectedResult'], $access->stringResemblesDN($case['input'])); - } - - public function testCacheUserHome() { - $this->connection->expects($this->once()) - ->method('writeToCache'); - - $this->access->cacheUserHome('foobar', '/foobars/path'); - } - - public function testBatchApplyUserAttributes() { - $this->ldap->expects($this->any()) - ->method('isResource') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('getAttributes') - ->willReturn(['displayname' => ['bar', 'count' => 1]]); - - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ - $mapperMock = $this->createMock(UserMapping::class); - $mapperMock->expects($this->any()) - ->method('getNameByDN') - ->willReturn(false); - $mapperMock->expects($this->any()) - ->method('map') - ->willReturn(true); - - $userMock = $this->createMock(User::class); - - // also returns for userUuidAttribute - $this->access->connection->expects($this->any()) - ->method('__get') - ->willReturn('displayName'); - - $this->access->setUserMapper($mapperMock); - - $displayNameAttribute = strtolower($this->access->connection->ldapUserDisplayName); - $data = [ - [ - 'dn' => ['foobar'], - $displayNameAttribute => 'barfoo' - ], - [ - 'dn' => ['foo'], - $displayNameAttribute => 'bar' - ], - [ - 'dn' => ['raboof'], - $displayNameAttribute => 'oofrab' - ] - ]; - - $userMock->expects($this->exactly(count($data))) - ->method('processAttributes'); - - $this->userManager->expects($this->exactly(count($data) * 2)) - ->method('get') - ->willReturn($userMock); - - $this->access->batchApplyUserAttributes($data); - } - - public function testBatchApplyUserAttributesSkipped() { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ - $mapperMock = $this->createMock(UserMapping::class); - $mapperMock->expects($this->any()) - ->method('getNameByDN') - ->willReturn('a_username'); - - $userMock = $this->createMock(User::class); - - $this->access->connection->expects($this->any()) - ->method('__get') - ->willReturn('displayName'); - - $this->access->setUserMapper($mapperMock); - - $displayNameAttribute = strtolower($this->access->connection->ldapUserDisplayName); - $data = [ - [ - 'dn' => ['foobar'], - $displayNameAttribute => 'barfoo' - ], - [ - 'dn' => ['foo'], - $displayNameAttribute => 'bar' - ], - [ - 'dn' => ['raboof'], - $displayNameAttribute => 'oofrab' - ] - ]; - - $userMock->expects($this->never()) - ->method('processAttributes'); - - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($this->createMock(User::class)); - - $this->access->batchApplyUserAttributes($data); - } - - public function testBatchApplyUserAttributesDontSkip() { - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ - $mapperMock = $this->createMock(UserMapping::class); - $mapperMock->expects($this->any()) - ->method('getNameByDN') - ->willReturn('a_username'); - - $userMock = $this->createMock(User::class); - - $this->access->connection->expects($this->any()) - ->method('__get') - ->willReturn('displayName'); - - $this->access->setUserMapper($mapperMock); - - $displayNameAttribute = strtolower($this->access->connection->ldapUserDisplayName); - $data = [ - [ - 'dn' => ['foobar'], - $displayNameAttribute => 'barfoo' - ], - [ - 'dn' => ['foo'], - $displayNameAttribute => 'bar' - ], - [ - 'dn' => ['raboof'], - $displayNameAttribute => 'oofrab' - ] - ]; - - $userMock->expects($this->exactly(count($data))) - ->method('processAttributes'); - - $this->userManager->expects($this->exactly(count($data) * 2)) - ->method('get') - ->willReturn($userMock); - - $this->access->batchApplyUserAttributes($data); - } - - public function dNAttributeProvider() { - // corresponds to Access::resemblesDN() - return [ - 'dn' => ['dn'], - 'uniqueMember' => ['uniquemember'], - 'member' => ['member'], - 'memberOf' => ['memberof'] - ]; - } - - /** - * @dataProvider dNAttributeProvider - * @param $attribute - */ - public function testSanitizeDN($attribute) { - list($lw, $con, $um, $helper) = $this->getConnectorAndLdapMock(); - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject $config */ - $config = $this->createMock(IConfig::class); - - $dnFromServer = 'cn=Mixed Cases,ou=Are Sufficient To,ou=Test,dc=example,dc=org'; - - $lw->expects($this->any()) - ->method('isResource') - ->willReturn(true); - $lw->expects($this->any()) - ->method('getAttributes') - ->willReturn([ - $attribute => ['count' => 1, $dnFromServer] - ]); - - $access = new Access($con, $lw, $um, $helper, $config, $this->ncUserManager, $this->logger); - $values = $access->readAttribute('uid=whoever,dc=example,dc=org', $attribute); - $this->assertSame($values[0], strtolower($dnFromServer)); - } - - - public function testSetPasswordWithDisabledChanges() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('LDAP password changes are disabled'); - - $this->connection - ->method('__get') - ->willReturn(false); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->access->setPassword('CN=foo', 'MyPassword'); - } - - public function testSetPasswordWithLdapNotAvailable() { - $this->connection - ->method('__get') - ->willReturn(true); - $connection = $this->createMock(LDAP::class); - $this->connection - ->expects($this->once()) - ->method('getConnectionResource') - ->willReturn($connection); - $this->ldap - ->expects($this->once()) - ->method('isResource') - ->with($connection) - ->willReturn(false); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertFalse($this->access->setPassword('CN=foo', 'MyPassword')); - } - - - public function testSetPasswordWithRejectedChange() { - $this->expectException(\OC\HintException::class); - $this->expectExceptionMessage('Password change rejected.'); - - $this->connection - ->method('__get') - ->willReturn(true); - $connection = $this->createMock(LDAP::class); - $this->connection - ->expects($this->once()) - ->method('getConnectionResource') - ->willReturn($connection); - $this->ldap - ->expects($this->once()) - ->method('isResource') - ->with($connection) - ->willReturn(true); - $this->ldap - ->expects($this->once()) - ->method('modReplace') - ->with($connection, 'CN=foo', 'MyPassword') - ->willThrowException(new ConstraintViolationException()); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->access->setPassword('CN=foo', 'MyPassword'); - } - - public function testSetPassword() { - $this->connection - ->method('__get') - ->willReturn(true); - $connection = $this->createMock(LDAP::class); - $this->connection - ->expects($this->once()) - ->method('getConnectionResource') - ->willReturn($connection); - $this->ldap - ->expects($this->once()) - ->method('isResource') - ->with($connection) - ->willReturn(true); - $this->ldap - ->expects($this->once()) - ->method('modReplace') - ->with($connection, 'CN=foo', 'MyPassword') - ->willReturn(true); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertTrue($this->access->setPassword('CN=foo', 'MyPassword')); - } - - protected function prepareMocksForSearchTests( - $base, - $fakeConnection, - $fakeSearchResultResource, - $fakeLdapEntries - ) { - $this->connection - ->expects($this->any()) - ->method('getConnectionResource') - ->willReturn($fakeConnection); - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($base) { - if (stripos($key, 'base') !== false) { - return [$base]; - } - return null; - }); - - $this->ldap - ->expects($this->any()) - ->method('isResource') - ->willReturnCallback(function ($resource) { - return is_resource($resource); - }); - $this->ldap - ->expects($this->any()) - ->method('errno') - ->willReturn(0); - $this->ldap - ->expects($this->once()) - ->method('search') - ->willReturn($fakeSearchResultResource); - $this->ldap - ->expects($this->exactly(1)) - ->method('getEntries') - ->willReturn($fakeLdapEntries); - - $this->helper->expects($this->any()) - ->method('sanitizeDN') - ->willReturnArgument(0); - } - - public function testSearchNoPagedSearch() { - // scenario: no pages search, 1 search base - $filter = 'objectClass=nextcloudUser'; - $base = 'ou=zombies,dc=foobar,dc=nextcloud,dc=com'; - - $fakeConnection = ldap_connect(); - $fakeSearchResultResource = ldap_connect(); - $fakeLdapEntries = [ - 'count' => 2, - [ - 'dn' => 'uid=sgarth,' . $base, - ], - [ - 'dn' => 'uid=wwilson,' . $base, - ] - ]; - - $expected = $fakeLdapEntries; - unset($expected['count']); - - $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries); - - /** @noinspection PhpUnhandledExceptionInspection */ - $result = $this->access->search($filter, $base); - $this->assertSame($expected, $result); - } - - public function testFetchListOfUsers() { - $filter = 'objectClass=nextcloudUser'; - $base = 'ou=zombies,dc=foobar,dc=nextcloud,dc=com'; - $attrs = ['dn', 'uid']; - - $fakeConnection = ldap_connect(); - $fakeSearchResultResource = ldap_connect(); - $fakeLdapEntries = [ - 'count' => 2, - [ - 'dn' => 'uid=sgarth,' . $base, - 'uid' => [ 'sgarth' ], - ], - [ - 'dn' => 'uid=wwilson,' . $base, - 'uid' => [ 'wwilson' ], - ] - ]; - $expected = $fakeLdapEntries; - unset($expected['count']); - array_walk($expected, function (&$v) { - $v['dn'] = [$v['dn']]; // dn is translated into an array internally for consistency - }); - - $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries); - - $this->connection->expects($this->exactly($fakeLdapEntries['count'])) - ->method('writeToCache') - ->with($this->stringStartsWith('userExists'), true); - - $this->userMapper->expects($this->exactly($fakeLdapEntries['count'])) - ->method('getNameByDN') - ->willReturnCallback(function ($fdn) { - $parts = ldap_explode_dn($fdn, false); - return $parts[0]; - }); - - /** @noinspection PhpUnhandledExceptionInspection */ - $list = $this->access->fetchListOfUsers($filter, $attrs); - $this->assertSame($expected, $list); - } - - public function testFetchListOfGroupsKnown() { - $filter = 'objectClass=nextcloudGroup'; - $attributes = ['cn', 'gidNumber', 'dn']; - $base = 'ou=SomeGroups,dc=my,dc=directory'; - - $fakeConnection = ldap_connect(); - $fakeSearchResultResource = ldap_connect(); - $fakeLdapEntries = [ - 'count' => 2, - [ - 'dn' => 'cn=Good Team,' . $base, - 'cn' => ['Good Team'], - ], - [ - 'dn' => 'cn=Another Good Team,' . $base, - 'cn' => ['Another Good Team'], - ] - ]; - - $this->prepareMocksForSearchTests($base, $fakeConnection, $fakeSearchResultResource, $fakeLdapEntries); - - $this->groupMapper->expects($this->any()) - ->method('getListOfIdsByDn') - ->willReturn([ - 'cn=Good Team,' . $base => 'Good_Team', - 'cn=Another Good Team,' . $base => 'Another_Good_Team', - ]); - $this->groupMapper->expects($this->never()) - ->method('getNameByDN'); - - $this->connection->expects($this->exactly(2)) - ->method('writeToCache'); - - $groups = $this->access->fetchListOfGroups($filter, $attributes); - $this->assertSame(2, count($groups)); - $this->assertSame('Good Team', $groups[0]['cn'][0]); - $this->assertSame('Another Good Team', $groups[1]['cn'][0]); - } - - public function intUsernameProvider() { - // system dependent :-/ - $translitExpected = @iconv('UTF-8', 'ASCII//TRANSLIT', 'fränk') ? 'frank' : 'frnk'; - - return [ - ['alice', 'alice'], - ['b/ob', 'bob'], - ['charly🐬', 'charly'], - ['debo rah', 'debo_rah'], - ['epost@poste.test', 'epost@poste.test'], - ['fränk', $translitExpected], - [' gerda ', 'gerda'], - ['🕱🐵🐘🐑', null], - [ - 'OneNameToRuleThemAllOneNameToFindThemOneNameToBringThemAllAndInTheDarknessBindThem', - '81ff71b5dd0f0092e2dc977b194089120093746e273f2ef88c11003762783127' - ] - ]; - } - - public function groupIDCandidateProvider() { - return [ - ['alice', 'alice'], - ['b/ob', 'b/ob'], - ['charly🐬', 'charly🐬'], - ['debo rah', 'debo rah'], - ['epost@poste.test', 'epost@poste.test'], - ['fränk', 'fränk'], - [' gerda ', 'gerda'], - ['🕱🐵🐘🐑', '🕱🐵🐘🐑'], - [ - 'OneNameToRuleThemAllOneNameToFindThemOneNameToBringThemAllAndInTheDarknessBindThem', - '81ff71b5dd0f0092e2dc977b194089120093746e273f2ef88c11003762783127' - ] - ]; - } - - /** - * @dataProvider intUsernameProvider - * - * @param $name - * @param $expected - */ - public function testSanitizeUsername($name, $expected) { - if ($expected === null) { - $this->expectException(\InvalidArgumentException::class); - } - $sanitizedName = $this->access->sanitizeUsername($name); - $this->assertSame($expected, $sanitizedName); - } - - /** - * @dataProvider groupIDCandidateProvider - */ - public function testSanitizeGroupIDCandidate(string $name, string $expected) { - $sanitizedName = $this->access->sanitizeGroupIDCandidate($name); - $this->assertSame($expected, $sanitizedName); - } - - public function testUserStateUpdate() { - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnMap([ - [ 'ldapUserDisplayName', 'displayName' ], - [ 'ldapUserDisplayName2', null], - ]); - - $offlineUserMock = $this->createMock(OfflineUser::class); - $offlineUserMock->expects($this->once()) - ->method('unmark'); - - $regularUserMock = $this->createMock(User::class); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->with('detta') - ->willReturnOnConsecutiveCalls($offlineUserMock, $regularUserMock); - - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject $mapperMock */ - $mapperMock = $this->createMock(UserMapping::class); - $mapperMock->expects($this->any()) - ->method('getNameByDN') - ->with('uid=detta,ou=users,dc=hex,dc=ample') - ->willReturn('detta'); - $this->access->setUserMapper($mapperMock); - - $records = [ - [ - 'dn' => ['uid=detta,ou=users,dc=hex,dc=ample'], - 'displayName' => ['Detta Detkova'], - ] - ]; - $this->access->nextcloudUserNames($records); - } -} diff --git a/apps/user_ldap/tests/ConfigurationTest.php b/apps/user_ldap/tests/ConfigurationTest.php deleted file mode 100644 index db119eb3bfe60..0000000000000 --- a/apps/user_ldap/tests/ConfigurationTest.php +++ /dev/null @@ -1,142 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Roeland Jago Douma - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\Configuration; - -class ConfigurationTest extends \Test\TestCase { - /** @var Configuration */ - protected $configuration; - - protected function setUp(): void { - parent::setUp(); - $this->configuration = new Configuration('t01', false); - } - - public function configurationDataProvider() { - $inputWithDN = [ - 'cn=someUsers,dc=example,dc=org', - ' ', - ' cn=moreUsers,dc=example,dc=org ' - ]; - $expectWithDN = [ - 'cn=someUsers,dc=example,dc=org', - 'cn=moreUsers,dc=example,dc=org' - ]; - - $inputNames = [ - ' uid ', - 'cn ', - ' ', - '', - ' whats my name', - ' ' - ]; - $expectedNames = ['uid', 'cn', 'whats my name']; - - $inputString = ' alea iacta est '; - $expectedString = 'alea iacta est'; - - $inputHomeFolder = [ - ' homeDirectory ', - ' attr:homeDirectory ', - ' ' - ]; - - $expectedHomeFolder = [ - 'attr:homeDirectory', 'attr:homeDirectory', '' - ]; - - $password = ' such a passw0rd '; - - return [ - 'set general base' => ['ldapBase', $inputWithDN, $expectWithDN], - 'set user base' => ['ldapBaseUsers', $inputWithDN, $expectWithDN], - 'set group base' => ['ldapBaseGroups', $inputWithDN, $expectWithDN], - - 'set search attributes users' => ['ldapAttributesForUserSearch', $inputNames, $expectedNames], - 'set search attributes groups' => ['ldapAttributesForGroupSearch', $inputNames, $expectedNames], - - 'set user filter objectclasses' => ['ldapUserFilterObjectclass', $inputNames, $expectedNames], - 'set user filter groups' => ['ldapUserFilterGroups', $inputNames, $expectedNames], - 'set group filter objectclasses' => ['ldapGroupFilterObjectclass', $inputNames, $expectedNames], - 'set group filter groups' => ['ldapGroupFilterGroups', $inputNames, $expectedNames], - 'set login filter attributes' => ['ldapLoginFilterAttributes', $inputNames, $expectedNames], - - 'set agent password' => ['ldapAgentPassword', $password, $password], - - 'set home folder, variant 1' => ['homeFolderNamingRule', $inputHomeFolder[0], $expectedHomeFolder[0]], - 'set home folder, variant 2' => ['homeFolderNamingRule', $inputHomeFolder[1], $expectedHomeFolder[1]], - 'set home folder, empty' => ['homeFolderNamingRule', $inputHomeFolder[2], $expectedHomeFolder[2]], - - // default behaviour, one case is enough, special needs must be tested - // individually - 'set string value' => ['ldapHost', $inputString, $expectedString], - - 'set avatar rule, default' => ['ldapUserAvatarRule', 'default', 'default'], - 'set avatar rule, none' => ['ldapUserAvatarRule', 'none', 'none'], - 'set avatar rule, data attribute' => ['ldapUserAvatarRule', 'data:jpegPhoto', 'data:jpegPhoto'], - - 'set external storage home attribute' => ['ldapExtStorageHomeAttribute', 'homePath', 'homePath'], - ]; - } - - /** - * @dataProvider configurationDataProvider - */ - public function testSetValue($key, $input, $expected) { - $this->configuration->setConfiguration([$key => $input]); - $this->assertSame($this->configuration->$key, $expected); - } - - public function avatarRuleValueProvider() { - return [ - ['none', []], - ['data:selfie', ['selfie']], - ['data:sELFie', ['selfie']], - ['data:', ['jpegphoto', 'thumbnailphoto']], - ['default', ['jpegphoto', 'thumbnailphoto']], - ['invalid#', ['jpegphoto', 'thumbnailphoto']], - ]; - } - - /** - * @dataProvider avatarRuleValueProvider - */ - public function testGetAvatarAttributes($setting, $expected) { - $this->configuration->setConfiguration(['ldapUserAvatarRule' => $setting]); - $this->assertSame($expected, $this->configuration->getAvatarAttributes()); - } - - /** - * @dataProvider avatarRuleValueProvider - */ - public function testResolveRule($setting, $expected) { - $this->configuration->setConfiguration(['ldapUserAvatarRule' => $setting]); - // so far the only thing that can get resolved :) - $this->assertSame($expected, $this->configuration->resolveRule('avatar')); - } -} diff --git a/apps/user_ldap/tests/ConnectionTest.php b/apps/user_ldap/tests/ConnectionTest.php deleted file mode 100644 index a4fcf03008378..0000000000000 --- a/apps/user_ldap/tests/ConnectionTest.php +++ /dev/null @@ -1,291 +0,0 @@ - - * @author Christoph Wurst - * @author Jarkko Lehtoranta - * @author Joas Schilling - * @author Julius Härtl - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Thomas Müller - * @author Victor Dubiniuk - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\ILDAPWrapper; - -/** - * Class Test_Connection - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class ConnectionTest extends \Test\TestCase { - /** @var \OCA\User_LDAP\ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject */ - protected $ldap; - - /** @var Connection */ - protected $connection; - - protected function setUp(): void { - parent::setUp(); - - $this->ldap = $this->createMock(ILDAPWrapper::class); - // we use a mock here to replace the cache mechanism, due to missing DI in LDAP backend. - $this->connection = $this->getMockBuilder('OCA\User_LDAP\Connection') - ->setMethods(['getFromCache', 'writeToCache']) - ->setConstructorArgs([$this->ldap, '', null]) - ->getMock(); - - $this->ldap->expects($this->any()) - ->method('areLDAPFunctionsAvailable') - ->willReturn(true); - } - - public function testOriginalAgentUnchangedOnClone() { - //background: upon login a bind is done with the user credentials - //which is valid for the whole LDAP resource. It needs to be reset - //to the agent's credentials - $lw = $this->createMock(ILDAPWrapper::class); - - $connection = new Connection($lw, '', null); - $agent = [ - 'ldapAgentName' => 'agent', - 'ldapAgentPassword' => '123456', - ]; - $connection->setConfiguration($agent); - - $testConnection = clone $connection; - $user = [ - 'ldapAgentName' => 'user', - 'ldapAgentPassword' => 'password', - ]; - $testConnection->setConfiguration($user); - - $agentName = $connection->ldapAgentName; - $agentPawd = $connection->ldapAgentPassword; - - $this->assertSame($agentName, $agent['ldapAgentName']); - $this->assertSame($agentPawd, $agent['ldapAgentPassword']); - } - - public function testUseBackupServer() { - $mainHost = 'ldap://nixda.ldap'; - $backupHost = 'ldap://fallback.ldap'; - $config = [ - 'ldapConfigurationActive' => true, - 'ldapHost' => $mainHost, - 'ldapPort' => 389, - 'ldapBackupHost' => $backupHost, - 'ldapBackupPort' => 389, - 'ldapAgentName' => 'uid=agent', - 'ldapAgentPassword' => 'SuchASecret' - ]; - - $this->connection->setIgnoreValidation(true); - $this->connection->setConfiguration($config); - - $this->ldap->expects($this->any()) - ->method('isResource') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('setOption') - ->willReturn(true); - - $this->ldap->expects($this->exactly(3)) - ->method('connect') - ->willReturn('ldapResource'); - - $this->ldap->expects($this->any()) - ->method('errno') - ->willReturn(0); - - // Not called often enough? Then, the fallback to the backup server is broken. - $this->connection->expects($this->exactly(4)) - ->method('getFromCache') - ->with('overrideMainServer') - ->will($this->onConsecutiveCalls(false, false, true, true)); - - $this->connection->expects($this->once()) - ->method('writeToCache') - ->with('overrideMainServer', true); - - $isThrown = false; - $this->ldap->expects($this->exactly(3)) - ->method('bind') - ->willReturnCallback(function () use (&$isThrown) { - if (!$isThrown) { - $isThrown = true; - throw new \OC\ServerNotAvailableException(); - } - return true; - }); - - $this->connection->init(); - $this->connection->resetConnectionResource(); - // with the second init() we test whether caching works - $this->connection->init(); - } - - public function testDontUseBackupServerOnFailedAuth() { - $mainHost = 'ldap://nixda.ldap'; - $backupHost = 'ldap://fallback.ldap'; - $config = [ - 'ldapConfigurationActive' => true, - 'ldapHost' => $mainHost, - 'ldapPort' => 389, - 'ldapBackupHost' => $backupHost, - 'ldapBackupPort' => 389, - 'ldapAgentName' => 'uid=agent', - 'ldapAgentPassword' => 'SuchASecret' - ]; - - $this->connection->setIgnoreValidation(true); - $this->connection->setConfiguration($config); - - $this->ldap->expects($this->any()) - ->method('isResource') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('setOption') - ->willReturn(true); - - $this->ldap->expects($this->once()) - ->method('connect') - ->willReturn('ldapResource'); - - $this->ldap->expects($this->any()) - ->method('errno') - ->willReturn(49); - - $this->connection->expects($this->any()) - ->method('getFromCache') - ->with('overrideMainServer') - ->willReturn(false); - - $this->connection->expects($this->never()) - ->method('writeToCache'); - - $this->ldap->expects($this->exactly(1)) - ->method('bind') - ->willReturn(false); - - $this->connection->init(); - } - - public function testBindWithInvalidCredentials() { - // background: Bind with invalid credentials should return false - // and not throw a ServerNotAvailableException. - - $host = 'ldap://nixda.ldap'; - $config = [ - 'ldapConfigurationActive' => true, - 'ldapHost' => $host, - 'ldapPort' => 389, - 'ldapBackupHost' => '', - 'ldapAgentName' => 'user', - 'ldapAgentPassword' => 'password' - ]; - - $this->connection->setIgnoreValidation(true); - $this->connection->setConfiguration($config); - - $this->ldap->expects($this->any()) - ->method('isResource') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('setOption') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('connect') - ->willReturn('ldapResource'); - - $this->ldap->expects($this->once()) - ->method('bind') - ->willReturn(false); - - // LDAP_INVALID_CREDENTIALS - $this->ldap->expects($this->any()) - ->method('errno') - ->willReturn(0x31); - - try { - $this->assertFalse($this->connection->bind(), 'Connection::bind() should not return true with invalid credentials.'); - } catch (\OC\ServerNotAvailableException $e) { - $this->fail('Failed asserting that exception of type "OC\ServerNotAvailableException" is not thrown.'); - } - } - - public function testStartTlsNegotiationFailure() { - // background: If Start TLS negotiation fails, - // a ServerNotAvailableException should be thrown. - - $host = 'ldap://nixda.ldap'; - $port = 389; - $config = [ - 'ldapConfigurationActive' => true, - 'ldapHost' => $host, - 'ldapPort' => $port, - 'ldapTLS' => true, - 'ldapBackupHost' => '', - 'ldapAgentName' => 'user', - 'ldapAgentPassword' => 'password' - ]; - - $this->connection->setIgnoreValidation(true); - $this->connection->setConfiguration($config); - - $this->ldap->expects($this->any()) - ->method('isResource') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('connect') - ->willReturn('ldapResource'); - - $this->ldap->expects($this->any()) - ->method('setOption') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('bind') - ->willReturn(true); - - $this->ldap->expects($this->any()) - ->method('errno') - ->willReturn(0); - - $this->ldap->expects($this->any()) - ->method('startTls') - ->willReturn(false); - - $this->expectException(\OC\ServerNotAvailableException::class); - $this->expectExceptionMessage('Start TLS failed, when connecting to LDAP host ' . $host . '.'); - - $this->connection->init(); - } -} diff --git a/apps/user_ldap/tests/GroupLDAPPluginTest.php b/apps/user_ldap/tests/GroupLDAPPluginTest.php deleted file mode 100644 index baabdfb53c46d..0000000000000 --- a/apps/user_ldap/tests/GroupLDAPPluginTest.php +++ /dev/null @@ -1,249 +0,0 @@ - - * @author Roeland Jago Douma - * @author Vinicius Cubas Brand - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\GroupPluginManager; -use OCP\GroupInterface; - -class GroupLDAPPluginTest extends \Test\TestCase { - - /** - * @return GroupPluginManager - */ - private function getGroupPluginManager() { - return new GroupPluginManager(); - } - - public function testImplementsActions() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::CREATE_GROUP); - - $plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions']) - ->getMock(); - - $plugin2->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::ADD_TO_GROUP); - - $pluginManager->register($plugin); - $pluginManager->register($plugin2); - - $this->assertEquals($pluginManager->getImplementedActions(), GroupInterface::CREATE_GROUP | GroupInterface::ADD_TO_GROUP); - $this->assertTrue($pluginManager->implementsActions(GroupInterface::CREATE_GROUP)); - $this->assertTrue($pluginManager->implementsActions(GroupInterface::ADD_TO_GROUP)); - } - - public function testCreateGroup() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'createGroup']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::CREATE_GROUP); - - $plugin->expects($this->once()) - ->method('createGroup') - ->with( - $this->equalTo('group') - ); - - $pluginManager->register($plugin); - $pluginManager->createGroup('group'); - } - - - public function testCreateGroupNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements createGroup in this LDAP Backend.'); - - $pluginManager = $this->getGroupPluginManager(); - $pluginManager->createGroup('foo'); - } - - public function testDeleteGroup() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'deleteGroup']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::DELETE_GROUP); - - $plugin->expects($this->once()) - ->method('deleteGroup') - ->with( - $this->equalTo('group') - ); - - $pluginManager->register($plugin); - $pluginManager->deleteGroup('group'); - } - - - public function testDeleteGroupNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements deleteGroup in this LDAP Backend.'); - - $pluginManager = $this->getGroupPluginManager(); - $pluginManager->deleteGroup('foo'); - } - - public function testAddToGroup() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'addToGroup']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::ADD_TO_GROUP); - - $plugin->expects($this->once()) - ->method('addToGroup') - ->with( - $this->equalTo('uid'), - $this->equalTo('gid') - ); - - $pluginManager->register($plugin); - $pluginManager->addToGroup('uid', 'gid'); - } - - - public function testAddToGroupNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements addToGroup in this LDAP Backend.'); - - $pluginManager = $this->getGroupPluginManager(); - $pluginManager->addToGroup('foo', 'bar'); - } - - public function testRemoveFromGroup() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'removeFromGroup']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::REMOVE_FROM_GROUP); - - $plugin->expects($this->once()) - ->method('removeFromGroup') - ->with( - $this->equalTo('uid'), - $this->equalTo('gid') - ); - - $pluginManager->register($plugin); - $pluginManager->removeFromGroup('uid', 'gid'); - } - - - public function testRemoveFromGroupNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements removeFromGroup in this LDAP Backend.'); - - $pluginManager = $this->getGroupPluginManager(); - $pluginManager->removeFromGroup('foo', 'bar'); - } - - public function testCountUsersInGroup() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'countUsersInGroup']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::COUNT_USERS); - - $plugin->expects($this->once()) - ->method('countUsersInGroup') - ->with( - $this->equalTo('gid'), - $this->equalTo('search') - ); - - $pluginManager->register($plugin); - $pluginManager->countUsersInGroup('gid', 'search'); - } - - - public function testCountUsersInGroupNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements countUsersInGroup in this LDAP Backend.'); - - $pluginManager = $this->getGroupPluginManager(); - $pluginManager->countUsersInGroup('foo', 'bar'); - } - - public function testgetGroupDetails() { - $pluginManager = $this->getGroupPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPGroupPluginDummy') - ->setMethods(['respondToActions', 'getGroupDetails']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(GroupInterface::GROUP_DETAILS); - - $plugin->expects($this->once()) - ->method('getGroupDetails') - ->with( - $this->equalTo('gid') - ); - - $pluginManager->register($plugin); - $pluginManager->getGroupDetails('gid'); - } - - - public function testgetGroupDetailsNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements getGroupDetails in this LDAP Backend.'); - - $pluginManager = $this->getGroupPluginManager(); - $pluginManager->getGroupDetails('foo'); - } -} diff --git a/apps/user_ldap/tests/Group_LDAPTest.php b/apps/user_ldap/tests/Group_LDAPTest.php deleted file mode 100644 index 1844e2deddcbc..0000000000000 --- a/apps/user_ldap/tests/Group_LDAPTest.php +++ /dev/null @@ -1,1383 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Thomas Müller - * @author Victor Dubiniuk - * @author Vincent Petry - * @author Vinicius Cubas Brand - * @author Xuanwo - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\Group_LDAP as GroupLDAP; -use OCA\User_LDAP\GroupPluginManager; -use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\User\Manager; -use OCP\GroupInterface; -use PHPUnit\Framework\MockObject\MockObject; -use Test\TestCase; - -/** - * Class GroupLDAPTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class Group_LDAPTest extends TestCase { - public function testCountEmptySearchString() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - $groupDN = 'cn=group,dc=foo,dc=bar'; - - $this->enableGroups($access); - - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturn($groupDN); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn) use ($groupDN) { - if ($dn === $groupDN) { - return [ - 'uid=u11,ou=users,dc=foo,dc=bar', - 'uid=u22,ou=users,dc=foo,dc=bar', - 'uid=u33,ou=users,dc=foo,dc=bar', - 'uid=u34,ou=users,dc=foo,dc=bar' - ]; - } - return []; - }); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - // for primary groups - $access->expects($this->once()) - ->method('countUsers') - ->willReturn(2); - - $access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['displayName', 'mail']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('group'); - - $this->assertSame(6, $users); - } - - /** - * @return MockObject|Access - */ - private function getAccessMock() { - static $conMethods; - static $accMethods; - - if (is_null($conMethods) || is_null($accMethods)) { - $conMethods = get_class_methods(Connection::class); - $accMethods = get_class_methods(Access::class); - } - $lw = $this->createMock(ILDAPWrapper::class); - $connector = $this->getMockBuilder(Connection::class) - ->setMethods($conMethods) - ->setConstructorArgs([$lw, null, null]) - ->getMock(); - - $access = $this->createMock(Access::class); - - $access->expects($this->any()) - ->method('getConnection') - ->willReturn($connector); - - $access->userManager = $this->createMock(Manager::class); - - return $access; - } - - /** - * @return MockObject|GroupPluginManager - */ - private function getPluginManagerMock() { - return $this->createMock(GroupPluginManager::class); - } - - private function enableGroups(Access $access) { - $access->connection = $this->createMock(Connection::class); - - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapDynamicGroupMemberURL') { - return ''; - } - return 1; - }); - } - - public function testCountWithSearchString() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturn('cn=group,dc=foo,dc=bar'); - $access->expects($this->any()) - ->method('fetchListOfUsers') - ->willReturn([]); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($name) { - //the search operation will call readAttribute, thus we need - //to anaylze the "dn". All other times we just need to return - //something that is neither null or false, but once an array - //with the users in the group – so we do so all other times for - //simplicicity. - if (strpos($name, 'u') === 0) { - return strpos($name, '3'); - } - return ['u11', 'u22', 'u33', 'u34']; - }); - $access->expects($this->any()) - ->method('dn2username') - ->willReturnCallback(function () { - return 'foobar' . \OC::$server->getSecureRandom()->generate(7); - }); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - $access->expects($this->any()) - ->method('escapeFilterPart') - ->willReturnArgument(0); - - $access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['displayName', 'mail']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('group', '3'); - - $this->assertSame(2, $users); - } - - public function testCountUsersWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'countUsersInGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::COUNT_USERS) - ->willReturn(true); - - $pluginManager->expects($this->once()) - ->method('countUsersInGroup') - ->with('gid', 'search') - ->willReturn(42); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->countUsersInGroup('gid', 'search'), 42); - } - - public function testGidNumber2NameSuccess() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('searchGroups') - ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - - $access->expects($this->once()) - ->method('dn2groupname') - ->with('cn=foo,dc=barfoo,dc=bar') - ->willReturn('MyGroup'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->gidNumber2Name('3117', $userDN); - - $this->assertSame('MyGroup', $group); - } - - public function testGidNumberID2NameNoGroup() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('searchGroups') - ->willReturn([]); - - $access->expects($this->never()) - ->method('dn2groupname'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->gidNumber2Name('3117', $userDN); - - $this->assertSame(false, $group); - } - - public function testGidNumberID2NameNoName() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('searchGroups') - ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - - $access->expects($this->once()) - ->method('dn2groupname') - ->willReturn(false); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->gidNumber2Name('3117', $userDN); - - $this->assertSame(false, $group); - } - - public function testGetEntryGidNumberValue() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; - $attr = 'gidNumber'; - - $access->expects($this->once()) - ->method('readAttribute') - ->with($dn, $attr) - ->willReturn(['3117']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupGidNumber($dn); - - $this->assertSame('3117', $gid); - } - - public function testGetEntryGidNumberNoValue() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; - $attr = 'gidNumber'; - - $access->expects($this->once()) - ->method('readAttribute') - ->with($dn, $attr) - ->willReturn(false); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupGidNumber($dn); - - $this->assertSame(false, $gid); - } - - public function testPrimaryGroupID2NameSuccessCache() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - $gid = '3117'; - $groupDN = 'cn=foo,dc=barfoo,dc=bar'; - - /** @var MockObject $connection */ - $connection = $access->connection; - $connection->expects($this->once()) - ->method('getFromCache') - ->with('primaryGroupIDtoName_' . $gid) - ->willReturn('MyGroup'); - - $access->expects($this->never()) - ->method('getSID'); - - $access->expects($this->never()) - ->method('searchGroups'); - - $access->expects($this->never()) - ->method('dn2groupname'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $group = $groupBackend->primaryGroupID2Name($gid, $userDN); - - $this->assertSame('MyGroup', $group); - } - - public function testPrimaryGroupID2NameSuccess() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('getSID') - ->with($userDN) - ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - - $access->expects($this->once()) - ->method('searchGroups') - ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - - $access->expects($this->once()) - ->method('dn2groupname') - ->with('cn=foo,dc=barfoo,dc=bar') - ->willReturn('MyGroup'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); - - $this->assertSame('MyGroup', $group); - } - - public function testPrimaryGroupID2NameNoSID() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('getSID') - ->with($userDN) - ->willReturn(false); - - $access->expects($this->never()) - ->method('searchGroups'); - - $access->expects($this->never()) - ->method('dn2groupname'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); - - $this->assertSame(false, $group); - } - - public function testPrimaryGroupID2NameNoGroup() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('getSID') - ->with($userDN) - ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - - $access->expects($this->once()) - ->method('searchGroups') - ->willReturn([]); - - $access->expects($this->never()) - ->method('dn2groupname'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); - - $this->assertSame(false, $group); - } - - public function testPrimaryGroupID2NameNoName() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $userDN = 'cn=alice,cn=foo,dc=barfoo,dc=bar'; - - $access->expects($this->once()) - ->method('getSID') - ->with($userDN) - ->willReturn('S-1-5-21-249921958-728525901-1594176202'); - - $access->expects($this->once()) - ->method('searchGroups') - ->willReturn([['dn' => ['cn=foo,dc=barfoo,dc=bar']]]); - - $access->expects($this->once()) - ->method('dn2groupname') - ->willReturn(false); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $group = $groupBackend->primaryGroupID2Name('3117', $userDN); - - $this->assertSame(false, $group); - } - - public function testGetEntryGroupIDValue() { - //tests getEntryGroupID via getGroupPrimaryGroupID - //which is basically identical to getUserPrimaryGroupIDs - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; - $attr = 'primaryGroupToken'; - - $access->expects($this->once()) - ->method('readAttribute') - ->with($dn, $attr) - ->willReturn(['3117']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupPrimaryGroupID($dn); - - $this->assertSame('3117', $gid); - } - - public function testGetEntryGroupIDNoValue() { - //tests getEntryGroupID via getGroupPrimaryGroupID - //which is basically identical to getUserPrimaryGroupIDs - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $dn = 'cn=foobar,cn=foo,dc=barfoo,dc=bar'; - $attr = 'primaryGroupToken'; - - $access->expects($this->once()) - ->method('readAttribute') - ->with($dn, $attr) - ->willReturn(false); - - $groupBackend = new GroupLDAP($access, $pluginManager); - - $gid = $groupBackend->getGroupPrimaryGroupID($dn); - - $this->assertSame(false, $gid); - } - - /** - * tests whether Group Backend behaves correctly when cache with uid and gid - * is hit - */ - public function testInGroupHitsUidGidCache() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $uid = 'someUser'; - $gid = 'someGroup'; - $cacheKey = 'inGroup' . $uid . ':' . $gid; - - $access->connection->expects($this->once()) - ->method('getFromCache') - ->with($cacheKey) - ->willReturn(true); - - $access->expects($this->never()) - ->method('username2dn'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $groupBackend->inGroup($uid, $gid); - } - - public function groupWithMembersProvider() { - return [ - [ - 'someGroup', - 'cn=someGroup,ou=allTheGroups,ou=someDepartment,dc=someDomain,dc=someTld', - [ - 'uid=oneUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', - 'uid=someUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', - 'uid=anotherUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', - 'uid=differentUser,ou=someTeam,ou=someDepartment,dc=someDomain,dc=someTld', - ], - ], - ]; - } - - /** - * @dataProvider groupWithMembersProvider - */ - public function testInGroupMember(string $gid, string $groupDn, array $memberDNs) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $access->connection = $this->createMock(Connection::class); - - $uid = 'someUser'; - $userDn = $memberDNs[0]; - - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - switch ($name) { - case 'ldapGroupMemberAssocAttr': - return 'member'; - case 'ldapDynamicGroupMemberURL': - return ''; - case 'hasPrimaryGroups': - case 'ldapNestedGroups': - return 0; - default: - return 1; - } - }); - $access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturn(null); - - $access->expects($this->once()) - ->method('username2dn') - ->with($uid) - ->willReturn($userDn); - $access->expects($this->once()) - ->method('groupname2dn') - ->willReturn($groupDn); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturn($memberDNs); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $this->assertTrue($groupBackend->inGroup($uid, $gid)); - } - - /** - * @dataProvider groupWithMembersProvider - */ - public function testInGroupMemberNot(string $gid, string $groupDn, array $memberDNs) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $access->connection = $this->createMock(Connection::class); - - $uid = 'unelatedUser'; - $userDn = 'uid=unrelatedUser,ou=unrelatedTeam,ou=unrelatedDepartment,dc=someDomain,dc=someTld'; - - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - switch ($name) { - case 'ldapGroupMemberAssocAttr': - return 'member'; - case 'ldapDynamicGroupMemberURL': - return ''; - case 'hasPrimaryGroups': - case 'ldapNestedGroups': - return 0; - default: - return 1; - } - }); - $access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturn(null); - - $access->expects($this->once()) - ->method('username2dn') - ->with($uid) - ->willReturn($userDn); - $access->expects($this->once()) - ->method('groupname2dn') - ->willReturn($groupDn); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturn($memberDNs); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $this->assertFalse($groupBackend->inGroup($uid, $gid)); - } - - /** - * @dataProvider groupWithMembersProvider - */ - public function testInGroupMemberUid(string $gid, string $groupDn, array $memberDNs) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $memberUids = []; - $userRecords = []; - foreach ($memberDNs as $dn) { - $memberUids[] = ldap_explode_dn($dn, false)[0]; - $userRecords[] = ['dn' => [$dn]]; - } - - - $access->connection = $this->createMock(Connection::class); - - $uid = 'someUser'; - $userDn = $memberDNs[0]; - - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - switch ($name) { - case 'ldapGroupMemberAssocAttr': - return 'memberUid'; - case 'ldapDynamicGroupMemberURL': - return ''; - case 'ldapLoginFilter': - return 'uid=%uid'; - case 'hasPrimaryGroups': - case 'ldapNestedGroups': - return 0; - default: - return 1; - } - }); - $access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturn(null); - - $access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['uid', 'mail', 'displayname']); - - $access->expects($this->once()) - ->method('username2dn') - ->with($uid) - ->willReturn($userDn); - $access->expects($this->once()) - ->method('groupname2dn') - ->willReturn($groupDn); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturn($memberUids); - $access->expects($this->any()) - ->method('fetchListOfUsers') - ->willReturn($userRecords); - $access->expects($this->any()) - ->method('combineFilterWithOr') - ->willReturn('(|(pseudo=filter)(filter=pseudo))'); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $this->assertTrue($groupBackend->inGroup($uid, $gid)); - } - - public function testGetGroupsWithOffset() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $access->expects($this->once()) - ->method('nextcloudGroupNames') - ->willReturn(['group1', 'group2']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getGroups('', 2, 2); - - $this->assertSame(2, count($groups)); - } - - /** - * tests that a user listing is complete, if all it's members have the group - * as their primary. - */ - public function testUsersInGroupPrimaryMembersOnly() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturn(null); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($attr === 'primaryGroupToken') { - return [1337]; - } elseif ($attr === 'gidNumber') { - return [4211]; - } - return []; - }); - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturn('cn=foobar,dc=foo,dc=bar'); - $access->expects($this->exactly(2)) - ->method('nextcloudUserNames') - ->willReturnOnConsecutiveCalls(['lisa', 'bart', 'kira', 'brad'], ['walle', 'dino', 'xenia']); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - $access->expects($this->any()) - ->method('combineFilterWithAnd') - ->willReturn('pseudo=filter'); - - $access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['displayName', 'mail']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->usersInGroup('foobar'); - - $this->assertSame(7, count($users)); - } - - /** - * tests that a user listing is complete, if all it's members have the group - * as their primary. - */ - public function testUsersInGroupPrimaryAndUnixMembers() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturn(null); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($attr === 'primaryGroupToken') { - return [1337]; - } - return []; - }); - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturn('cn=foobar,dc=foo,dc=bar'); - $access->expects($this->once()) - ->method('nextcloudUserNames') - ->willReturn(['lisa', 'bart', 'kira', 'brad']); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - $access->expects($this->any()) - ->method('combineFilterWithAnd') - ->willReturn('pseudo=filter'); - - $access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['displayName', 'mail']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->usersInGroup('foobar'); - - $this->assertSame(4, count($users)); - } - - /** - * tests that a user counting is complete, if all it's members have the group - * as their primary. - */ - public function testCountUsersInGroupPrimaryMembersOnly() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturn(null); - - $access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($attr === 'primaryGroupToken') { - return [1337]; - } - return []; - }); - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturn('cn=foobar,dc=foo,dc=bar'); - $access->expects($this->once()) - ->method('countUsers') - ->willReturn(4); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - - $access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['displayName', 'mail']); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $users = $groupBackend->countUsersInGroup('foobar'); - - $this->assertSame(4, $users); - } - - public function testGetUserGroupsMemberOf() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $this->enableGroups($access); - - $dn = 'cn=userX,dc=foobar'; - - $access->connection->hasPrimaryGroups = false; - $access->connection->hasGidNumber = false; - - $access->expects($this->any()) - ->method('username2dn') - ->willReturn($dn); - $access->expects($this->exactly(5)) - ->method('readAttribute') - ->will($this->onConsecutiveCalls(['cn=groupA,dc=foobar', 'cn=groupB,dc=foobar'], [], [], [], [])); - $access->expects($this->any()) - ->method('dn2groupname') - ->willReturnArgument(0); - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturnArgument(0); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getUserGroups('userX'); - - $this->assertSame(2, count($groups)); - } - - public function testGetUserGroupsMemberOfDisabled() { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'useMemberOfToDetectMembership') { - return 0; - } elseif ($name === 'ldapDynamicGroupMemberURL') { - return ''; - } - return 1; - }); - - $dn = 'cn=userX,dc=foobar'; - - $access->connection->hasPrimaryGroups = false; - $access->connection->hasGidNumber = false; - - $access->expects($this->once()) - ->method('username2dn') - ->willReturn($dn); - $access->expects($this->never()) - ->method('readAttribute') - ->with($dn, 'memberOf'); - $access->expects($this->once()) - ->method('nextcloudGroupNames') - ->willReturn([]); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $groupBackend->getUserGroups('userX'); - } - - public function nestedGroupsProvider(): array { - return [ - [true], - [false], - ]; - } - - /** - * @dataProvider nestedGroupsProvider - */ - public function testGetGroupsByMember(bool $nestedGroups) { - $access = $this->getAccessMock(); - $pluginManager = $this->getPluginManagerMock(); - - $groupFilter = '(&(objectclass=nextcloudGroup)(nextcloudEnabled=TRUE))'; - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) use ($nestedGroups, $groupFilter) { - switch ($name) { - case 'useMemberOfToDetectMembership': - return 0; - case 'ldapDynamicGroupMemberURL': - return ''; - case 'ldapNestedGroups': - return $nestedGroups; - case 'ldapGroupMemberAssocAttr': - return 'member'; - case 'ldapGroupFilter': - return $groupFilter; - } - return 1; - }); - - $dn = 'cn=userX,dc=foobar'; - - $access->connection->hasPrimaryGroups = false; - $access->connection->hasGidNumber = false; - - $access->expects($this->exactly(2)) - ->method('username2dn') - ->willReturn($dn); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturn([]); - $access->expects($this->any()) - ->method('combineFilterWithAnd') - ->willReturnCallback(function (array $filterParts) { - // ⚠ returns a pseudo-filter only, not real LDAP Filter syntax - return implode('&', $filterParts); - }); - - $group1 = [ - 'cn' => 'group1', - 'dn' => ['cn=group1,ou=groups,dc=domain,dc=com'], - ]; - $group2 = [ - 'cn' => 'group2', - 'dn' => ['cn=group2,ou=groups,dc=domain,dc=com'], - ]; - - $access->expects($this->once()) - ->method('nextcloudGroupNames') - ->with([$group1, $group2]) - ->willReturn(['group1', 'group2']); - $access->expects($nestedGroups ? $this->atLeastOnce() : $this->once()) - ->method('fetchListOfGroups') - ->willReturnCallback(function ($filter, $attr, $limit, $offset) use ($nestedGroups, $groupFilter, $group1, $group2) { - static $firstRun = true; - if (!$nestedGroups) { - // When nested groups are enabled, groups cannot be filtered early as it would - // exclude intermediate groups. But we can, and should, when working with flat groups. - $this->assertTrue(strpos($filter, $groupFilter) !== false); - } - if ($firstRun) { - $firstRun = false; - return [$group1, $group2]; - } - return []; - }); - $access->expects($this->any()) - ->method('dn2groupname') - ->willReturnCallback(function (string $dn) { - return ldap_explode_dn($dn, 1)[0]; - }); - $access->expects($this->any()) - ->method('groupname2dn') - ->willReturnCallback(function (string $gid) use ($group1, $group2) { - if ($gid === $group1['cn']) { - return $group1['dn'][0]; - } - if ($gid === $group2['cn']) { - return $group2['dn'][0]; - } - }); - $access->expects($this->any()) - ->method('isDNPartOfBase') - ->willReturn(true); - - $groupBackend = new GroupLDAP($access, $pluginManager); - $groups = $groupBackend->getUserGroups('userX'); - $this->assertEquals(['group1', 'group2'], $groups); - - $groupsAgain = $groupBackend->getUserGroups('userX'); - $this->assertEquals(['group1', 'group2'], $groupsAgain); - } - - public function testCreateGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'createGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::CREATE_GROUP) - ->willReturn(true); - - $pluginManager->expects($this->once()) - ->method('createGroup') - ->with('gid') - ->willReturn('result'); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->createGroup('gid'), true); - } - - - public function testCreateGroupFailing() { - $this->expectException(\Exception::class); - - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'createGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::CREATE_GROUP) - ->willReturn(false); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->createGroup('gid'); - } - - public function testDeleteGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'deleteGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::DELETE_GROUP) - ->willReturn(true); - - $pluginManager->expects($this->once()) - ->method('deleteGroup') - ->with('gid') - ->willReturn('result'); - - $mapper = $this->getMockBuilder(GroupMapping::class) - ->setMethods(['unmap']) - ->disableOriginalConstructor() - ->getMock(); - - $access = $this->getAccessMock(); - $access->expects($this->any()) - ->method('getGroupMapper') - ->willReturn($mapper); - - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->deleteGroup('gid'), 'result'); - } - - - public function testDeleteGroupFailing() { - $this->expectException(\Exception::class); - - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'deleteGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::DELETE_GROUP) - ->willReturn(false); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->deleteGroup('gid'); - } - - public function testAddToGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'addToGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::ADD_TO_GROUP) - ->willReturn(true); - - $pluginManager->expects($this->once()) - ->method('addToGroup') - ->with('uid', 'gid') - ->willReturn('result'); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->addToGroup('uid', 'gid'), 'result'); - } - - - public function testAddToGroupFailing() { - $this->expectException(\Exception::class); - - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'addToGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::ADD_TO_GROUP) - ->willReturn(false); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->addToGroup('uid', 'gid'); - } - - public function testRemoveFromGroupWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'removeFromGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::REMOVE_FROM_GROUP) - ->willReturn(true); - - $pluginManager->expects($this->once()) - ->method('removeFromGroup') - ->with('uid', 'gid') - ->willReturn('result'); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->removeFromGroup('uid', 'gid'), 'result'); - } - - - public function testRemoveFromGroupFailing() { - $this->expectException(\Exception::class); - - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'removeFromGroup']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::REMOVE_FROM_GROUP) - ->willReturn(false); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->removeFromGroup('uid', 'gid'); - } - - public function testGetGroupDetailsWithPlugin() { - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'getGroupDetails']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::GROUP_DETAILS) - ->willReturn(true); - - $pluginManager->expects($this->once()) - ->method('getGroupDetails') - ->with('gid') - ->willReturn('result'); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $this->assertEquals($ldap->getGroupDetails('gid'), 'result'); - } - - - public function testGetGroupDetailsFailing() { - $this->expectException(\Exception::class); - - /** @var GroupPluginManager|MockObject $pluginManager */ - $pluginManager = $this->getMockBuilder(GroupPluginManager::class) - ->setMethods(['implementsActions', 'getGroupDetails']) - ->getMock(); - - $pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(GroupInterface::GROUP_DETAILS) - ->willReturn(false); - - $access = $this->getAccessMock(); - $access->connection = $this->createMock(Connection::class); - - $ldap = new GroupLDAP($access, $pluginManager); - - $ldap->getGroupDetails('gid'); - } - - public function groupMemberProvider() { - $base = 'dc=species,dc=earth'; - - $groups0 = [ - 'uid=3723,' . $base, - 'uid=8372,' . $base, - 'uid=8427,' . $base, - 'uid=2333,' . $base, - 'uid=4754,' . $base, - ]; - $groups1 = [ - '3723', - '8372', - '8427', - '2333', - '4754', - ]; - $groups2Nested = ['6642', '1424']; - $expGroups2 = array_merge($groups1, $groups2Nested); - - return [ - [ #0 – test DNs - 'cn=Birds,' . $base, - $groups0, - ['cn=Birds,' . $base => $groups0] - ], - [ #1 – test uids - 'cn=Birds,' . $base, - $groups1, - ['cn=Birds,' . $base => $groups1] - ], - ]; - } - - /** - * @param string $groupDN - * @param string[] $expectedMembers - * @param array $groupsInfo - * @dataProvider groupMemberProvider - */ - public function testGroupMembers($groupDN, $expectedMembers, $groupsInfo = null) { - $access = $this->getAccessMock(); - $access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($group) use ($groupDN, $expectedMembers, $groupsInfo) { - if (isset($groupsInfo[$group])) { - return $groupsInfo[$group]; - } - return []; - }); - - $access->connection = $this->createMock(Connection::class); - if (count($groupsInfo) > 1) { - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapNestedGroups') { - return 1; - } - return null; - }); - } - - /** @var GroupPluginManager $pluginManager */ - $pluginManager = $this->createMock(GroupPluginManager::class); - - $ldap = new GroupLDAP($access, $pluginManager); - $resultingMembers = $this->invokePrivate($ldap, '_groupMembers', [$groupDN]); - - $this->assertEqualsCanonicalizing($expectedMembers, $resultingMembers); - } - - public function displayNameProvider() { - return [ - ['Graphic Novelists', ['Graphic Novelists']], - ['', false], - ]; - } - - /** - * @dataProvider displayNameProvider - */ - public function testGetDisplayName(string $expected, $ldapResult) { - $gid = 'graphic_novelists'; - - $access = $this->getAccessMock(); - $access->expects($this->atLeastOnce()) - ->method('readAttribute') - ->willReturn($ldapResult); - - $access->connection = $this->createMock(Connection::class); - $access->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapGroupMemberAssocAttr') { - return 'member'; - } elseif ($name === 'ldapGroupFilter') { - return 'objectclass=nextcloudGroup'; - } elseif ($name === 'ldapGroupDisplayName') { - return 'cn'; - } - return null; - }); - - /** @var GroupPluginManager $pluginManager */ - $pluginManager = $this->createMock(GroupPluginManager::class); - - $ldap = new GroupLDAP($access, $pluginManager); - $this->assertSame($expected, $ldap->getDisplayName($gid)); - } -} diff --git a/apps/user_ldap/tests/HelperTest.php b/apps/user_ldap/tests/HelperTest.php deleted file mode 100644 index 1822c27a1cdd8..0000000000000 --- a/apps/user_ldap/tests/HelperTest.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\Helper; -use OCP\IConfig; - -class HelperTest extends \Test\TestCase { - - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - - /** @var Helper */ - private $helper; - - protected function setUp(): void { - parent::setUp(); - - $this->config = $this->createMock(IConfig::class); - $this->helper = new Helper($this->config); - } - - public function testGetServerConfigurationPrefixes() { - $this->config->method('getAppKeys') - ->with($this->equalTo('user_ldap')) - ->willReturn([ - 'foo', - 'ldap_configuration_active', - 's1ldap_configuration_active', - ]); - - $result = $this->helper->getServerConfigurationPrefixes(false); - - $this->assertEquals(['', 's1'], $result); - } - - public function testGetServerConfigurationPrefixesActive() { - $this->config->method('getAppKeys') - ->with($this->equalTo('user_ldap')) - ->willReturn([ - 'foo', - 'ldap_configuration_active', - 's1ldap_configuration_active', - ]); - - $this->config->method('getAppValue') - ->willReturnCallback(function ($app, $key, $default) { - if ($app !== 'user_ldap') { - $this->fail('wrong app'); - } - if ($key === 's1ldap_configuration_active') { - return '1'; - } - return $default; - }); - - $result = $this->helper->getServerConfigurationPrefixes(true); - - $this->assertEquals(['s1'], $result); - } - - public function testGetServerConfigurationHost() { - $this->config->method('getAppKeys') - ->with($this->equalTo('user_ldap')) - ->willReturn([ - 'foo', - 'ldap_host', - 's1ldap_host', - 's02ldap_host', - ]); - - $this->config->method('getAppValue') - ->willReturnCallback(function ($app, $key, $default) { - if ($app !== 'user_ldap') { - $this->fail('wrong app'); - } - if ($key === 'ldap_host') { - return 'example.com'; - } - if ($key === 's1ldap_host') { - return 'foo.bar.com'; - } - return $default; - }); - - $result = $this->helper->getServerConfigurationHosts(); - - $this->assertEquals([ - '' => 'example.com', - 's1' => 'foo.bar.com', - 's02' => '', - ], $result); - } -} diff --git a/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php b/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php deleted file mode 100644 index acca987a81d6c..0000000000000 --- a/apps/user_ldap/tests/Integration/AbstractIntegrationTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * @author root - * @author Vinicius Cubas Brand - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\GroupPluginManager; -use OCA\User_LDAP\Helper; -use OCA\User_LDAP\LDAP; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\Manager; -use OCA\User_LDAP\UserPluginManager; - -abstract class AbstractIntegrationTest { - /** @var LDAP */ - protected $ldap; - - /** @var Connection */ - protected $connection; - - /** @var Access */ - protected $access; - - /** @var Manager */ - protected $userManager; - - /** @var Helper */ - protected $helper; - - /** @var string */ - protected $base; - - /** @var string[] */ - protected $server; - - public function __construct($host, $port, $bind, $pwd, $base) { - $this->base = $base; - $this->server = [ - 'host' => $host, - 'port' => $port, - 'dn' => $bind, - 'pwd' => $pwd - ]; - } - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - \OC::$server->registerService(UserPluginManager::class, function () { - return new \OCA\User_LDAP\UserPluginManager(); - }); - \OC::$server->registerService(GroupPluginManager::class, function () { - return new \OCA\User_LDAP\GroupPluginManager(); - }); - - $this->initLDAPWrapper(); - $this->initConnection(); - $this->initUserManager(); - $this->initHelper(); - $this->initAccess(); - } - - /** - * initializes the test LDAP wrapper - */ - protected function initLDAPWrapper() { - $this->ldap = new LDAP(); - } - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - $this->connection = new Connection($this->ldap, '', null); - $this->connection->setConfiguration([ - 'ldapHost' => $this->server['host'], - 'ldapPort' => $this->server['port'], - 'ldapBase' => $this->base, - 'ldapAgentName' => $this->server['dn'], - 'ldapAgentPassword' => $this->server['pwd'], - 'ldapUserFilter' => 'objectclass=inetOrgPerson', - 'ldapUserDisplayName' => 'cn', - 'ldapGroupDisplayName' => 'cn', - 'ldapLoginFilter' => '(|(uid=%uid)(samaccountname=%uid))', - 'ldapCacheTTL' => 0, - 'ldapConfigurationActive' => 1, - ]); - } - - /** - * initializes an LDAP user manager instance - */ - protected function initUserManager() { - $this->userManager = new Manager( - \OC::$server->getConfig(), - new FilesystemHelper(), - new LogWrapper(), - \OC::$server->getAvatarManager(), - new \OCP\Image(), - \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getNotificationManager() - ); - } - - /** - * initializes the test Helper - */ - protected function initHelper() { - $this->helper = new Helper(\OC::$server->getConfig()); - } - - /** - * initializes the Access test instance - */ - protected function initAccess() { - $this->access = new Access($this->connection, $this->ldap, $this->userManager, $this->helper, \OC::$server->getConfig(), \OC::$server->getLogger()); - } - - /** - * runs the test cases while outputting progress and result information - * - * If a test failed, the script is exited with return code 1. - */ - public function run() { - $methods = get_class_methods($this); - $atLeastOneCaseRan = false; - foreach ($methods as $method) { - if (strpos($method, 'case') === 0) { - print("running $method " . PHP_EOL); - try { - if (!$this->$method()) { - print(PHP_EOL . '>>> !!! Test ' . $method . ' FAILED !!! <<<' . PHP_EOL . PHP_EOL); - exit(1); - } - $atLeastOneCaseRan = true; - } catch (\Exception $e) { - print(PHP_EOL . '>>> !!! Test ' . $method . ' RAISED AN EXCEPTION !!! <<<' . PHP_EOL); - print($e->getMessage() . PHP_EOL . PHP_EOL); - exit(1); - } - } - } - if ($atLeastOneCaseRan) { - print('Tests succeeded' . PHP_EOL); - } else { - print('No Test was available.' . PHP_EOL); - exit(1); - } - } -} diff --git a/apps/user_ldap/tests/Integration/Bootstrap.php b/apps/user_ldap/tests/Integration/Bootstrap.php deleted file mode 100644 index afa92dac958f1..0000000000000 --- a/apps/user_ldap/tests/Integration/Bootstrap.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * @author Arthur Schiwon - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -define('CLI_TEST_RUN', true); -require_once __DIR__ . '/../../../../lib/base.php'; -require_once __DIR__ . '/setup-scripts/config.php'; diff --git a/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php b/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php deleted file mode 100644 index e78208e579c75..0000000000000 --- a/apps/user_ldap/tests/Integration/ExceptionOnLostConnection.php +++ /dev/null @@ -1,198 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration; - -use OC\ServerNotAvailableException; -use OCA\User_LDAP\LDAP; - -/** - * Class ExceptionOnLostConnection - * - * integration test, ensures that an exception is thrown, when the connection is lost. - * - * LDAP must be available via toxiproxy. - * - * This test must be run manually. - * - */ -class ExceptionOnLostConnection { - /** @var string */ - private $toxiProxyHost; - - /** @var string */ - private $toxiProxyName; - - /** @var string */ - private $ldapBase; - - /** @var string|null */ - private $ldapBindDN; - - /** @var string|null */ - private $ldapBindPwd; - - /** @var string */ - private $ldapHost; - - /** @var \OCA\User_LDAP\LDAP */ - private $ldap; - - /** @var bool */ - private $originalProxyState; - - /** - * @param string $proxyHost host of toxiproxy as url, like http://localhost:8474 - * @param string $proxyName name of the LDAP proxy service as configured in toxiProxy - * @param string $ldapBase any valid LDAP base DN - * @param null $bindDN optional, bind DN if anonymous bind is not possible - * @param null $bindPwd optional - */ - public function __construct($proxyHost, $proxyName, $ldapBase, $bindDN = null, $bindPwd = null) { - $this->toxiProxyHost = $proxyHost; - $this->toxiProxyName = $proxyName; - $this->ldapBase = $ldapBase; - $this->ldapBindDN = $bindDN; - $this->ldapBindPwd = $bindPwd; - - $this->setUp(); - } - - /** - * destructor - */ - public function __destruct() { - $this->cleanUp(); - } - - /** - * prepares everything for the test run. Includes loading Nextcloud and - * the LDAP backend, as well as getting information about toxiproxy. - * Also creates an instance of the LDAP class, the testee - * - * @throws \Exception - */ - public function setUp(): void { - require_once __DIR__ . '/../../../../lib/base.php'; - \OC_App::loadApps(['user_ldap']); - - $ch = $this->getCurl(); - $proxyInfoJson = curl_exec($ch); - $this->checkCurlResult($ch, $proxyInfoJson); - $proxyInfo = json_decode($proxyInfoJson, true); - $this->originalProxyState = $proxyInfo['enabled']; - $this->ldapHost = 'ldap://' . $proxyInfo['listen']; // contains port as well - - $this->ldap = new LDAP(); - } - - /** - * restores original state of the LDAP proxy, if necessary - */ - public function cleanUp() { - if ($this->originalProxyState === true) { - $this->setProxyState(true); - } - } - - /** - * runs the test and prints the result. Exit code is 0 if successful, 1 on - * fail - */ - public function run() { - if ($this->originalProxyState === false) { - $this->setProxyState(true); - } - //host contains port, 2nd parameter will be ignored - $cr = $this->ldap->connect($this->ldapHost, 0); - $this->ldap->bind($cr, $this->ldapBindDN, $this->ldapBindPwd); - $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', ['dn'], true, 5); - - // disable LDAP, will cause lost connection - $this->setProxyState(false); - try { - $this->ldap->search($cr, $this->ldapBase, 'objectClass=*', ['dn'], true, 5); - } catch (ServerNotAvailableException $e) { - print("Test PASSED" . PHP_EOL); - exit(0); - } - print("Test FAILED" . PHP_EOL); - exit(1); - } - - /** - * tests whether a curl operation ran successfully. If not, an exception - * is thrown - * - * @param resource $ch - * @param mixed $result - * @throws \Exception - */ - private function checkCurlResult($ch, $result) { - if ($result === false) { - $error = curl_error($ch); - curl_close($ch); - throw new \Exception($error); - } - } - - /** - * enables or disabled the LDAP proxy service in toxiproxy - * - * @param bool $isEnabled whether is should be enabled or disables - * @throws \Exception - */ - private function setProxyState($isEnabled) { - if (!is_bool($isEnabled)) { - throw new \InvalidArgumentException('Bool expected'); - } - $postData = json_encode(['enabled' => $isEnabled]); - $ch = $this->getCurl(); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); - curl_setopt($ch, CURLOPT_HTTPHEADER, [ - 'Content-Type: application/json', - 'Content-Length: ' . strlen($postData)] - ); - $recvd = curl_exec($ch); - $this->checkCurlResult($ch, $recvd); - } - - /** - * initializes a curl handler towards the toxiproxy LDAP proxy service - * @return resource - */ - private function getCurl() { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $this->toxiProxyHost . '/proxies/' . $this->toxiProxyName); - curl_setopt($ch, CURLOPT_HEADER, false); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - return $ch; - } -} - -$test = new ExceptionOnLostConnection('http://localhost:8474', 'ldap', 'dc=owncloud,dc=bzoc'); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php deleted file mode 100644 index 5669e2164b724..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestAttributeDetection.php +++ /dev/null @@ -1,89 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Morris Jobke - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\user_ldap\tests\Integration\Lib; - -use OCA\User_LDAP\Group_LDAP; -use OCA\User_LDAP\GroupPluginManager; -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\UserPluginManager; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestAttributeDetection extends AbstractIntegrationTest { - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - require(__DIR__ . '/../setup-scripts/createExplicitGroups.php'); - - parent::init(); - - $this->connection->setConfiguration(['ldapGroupFilter' => 'objectClass=groupOfNames']); - $this->connection->setConfiguration(['ldapGroupMemberAssocAttr' => 'member']); - - $userMapper = new UserMapping(\OC::$server->getDatabaseConnection()); - $userMapper->clear(); - $this->access->setUserMapper($userMapper); - - $groupMapper = new GroupMapping(\OC::$server->getDatabaseConnection()); - $groupMapper->clear(); - $this->access->setGroupMapper($groupMapper); - - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query(UserPluginManager::class)); - $userManager = \OC::$server->getUserManager(); - $userManager->clearBackends(); - $userManager->registerBackend($userBackend); - - $groupBackend = new Group_LDAP($this->access, \OC::$server->query(GroupPluginManager::class)); - $groupManger = \OC::$server->getGroupManager(); - $groupManger->clearBackends(); - $groupManger->addBackend($groupBackend); - } - - protected function caseNativeUUIDAttributeUsers() { - // trigger importing of users which also triggers UUID attribute detection - \OC::$server->getUserManager()->search('', 5, 0); - return $this->connection->ldapUuidUserAttribute === 'entryuuid'; - } - - protected function caseNativeUUIDAttributeGroups() { - // essentially the same as 'caseNativeUUIDAttributeUsers', code paths - // are similar, but we take no chances. - - // trigger importing of users which also triggers UUID attribute detection - \OC::$server->getGroupManager()->search('', 5, 0); - return $this->connection->ldapUuidGroupAttribute === 'entryuuid'; - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestAttributeDetection($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php deleted file mode 100644 index dc483ebec6d34..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestCountUsersByLoginName.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @author Joas Schilling - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestCountUsersByLoginName extends AbstractIntegrationTest { - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - parent::init(); - } - - /** - * tests countUsersByLoginName where it is expected that the login name does - * not match any LDAP user - * - * @return bool - */ - protected function case1() { - $result = $this->access->countUsersByLoginName('nothere'); - return $result === 0; - } - - /** - * tests countUsersByLoginName where it is expected that the login name does - * match one LDAP user - * - * @return bool - */ - protected function case2() { - $result = $this->access->countUsersByLoginName('alice'); - return $result === 1; - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestCountUsersByLoginName($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php deleted file mode 100644 index 7fc109966404d..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestFetchUsersByLoginName.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\UserPluginManager; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestFetchUsersByLoginName extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** @var User_LDAP */ - protected $backend; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - parent::init(); - - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); - $this->mapping->clear(); - $this->access->setUserMapper($this->mapping); - $this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query(UserPluginManager::class)); - } - - /** - * tests fetchUserByLoginName where it is expected that the login name does - * not match any LDAP user - * - * @return bool - */ - protected function case1() { - $result = $this->access->fetchUsersByLoginName('nothere'); - return $result === []; - } - - /** - * tests fetchUserByLoginName where it is expected that the login name does - * match one LDAP user - * - * @return bool - */ - protected function case2() { - $result = $this->access->fetchUsersByLoginName('alice'); - return count($result) === 1; - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestFetchUsersByLoginName($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php b/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php deleted file mode 100644 index 066c91a149baa..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/IntegrationTestPaging.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib; - -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\UserPluginManager; - -require_once __DIR__ . '/../Bootstrap.php'; - -class IntegrationTestPaging extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** @var User_LDAP */ - protected $backend; - - /** @var int */ - protected $pagingSize = 2; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../setup-scripts/createExplicitUsers.php'); - parent::init(); - - $this->backend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query(UserPluginManager::class)); - } - - public function initConnection() { - parent::initConnection(); - $this->connection->setConfiguration([ - 'ldapPagingSize' => $this->pagingSize - ]); - } - - /** - * fetch first three, afterwards all users - * - * @return bool - */ - protected function case1() { - $filter = 'objectclass=inetorgperson'; - $attributes = ['cn', 'dn']; - - $result = $this->access->searchUsers($filter, $attributes, 4); - // beware, under circumstances, the result set can be larger then - // the specified limit! In this case, if we specify a limit of 3, - // the result will be 4, because the highest possible paging size - // is 2 (as configured). - // But also with more than one search base, the limit can be outpaced. - if (count($result) !== 4) { - return false; - } - - $result = $this->access->searchUsers($filter, $attributes); - if (count($result) !== 7) { - return false; - } - - return true; - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestPaging($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php deleted file mode 100644 index 8c0bf6cde864c..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserAvatar.php +++ /dev/null @@ -1,168 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Roger Szabo - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib\User; - -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\User\Manager; -use OCA\User_LDAP\User\User; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\UserPluginManager; -use OCP\Image; - -require_once __DIR__ . '/../../Bootstrap.php'; - -class IntegrationTestUserAvatar extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php'); - parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); - $this->mapping->clear(); - $this->access->setUserMapper($this->mapping); - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query(UserPluginManager::class)); - \OC_User::useBackend($userBackend); - } - - /** - * A method that does the common steps of test cases 1 and 2. The evaluation - * is not happening here. - * - * @param string $dn - * @param string $username - * @param string $image - */ - private function execFetchTest($dn, $username, $image) { - $this->setJpegPhotoAttribute($dn, $image); - - // assigns our self-picked oc username to the dn - $this->mapping->map($dn, $username, 'fakeUUID-' . $username); - - // initialize home folder and make sure that the user will update - // also remove an possibly existing avatar - \OC_Util::tearDownFS(); - \OC_Util::setupFS($username); - \OC::$server->getUserFolder($username); - \OC::$server->getConfig()->deleteUserValue($username, 'user_ldap', User::USER_PREFKEY_LASTREFRESH); - if (\OC::$server->getAvatarManager()->getAvatar($username)->exists()) { - \OC::$server->getAvatarManager()->getAvatar($username)->remove(); - } - - // finally attempt to get the avatar set - $user = $this->userManager->get($dn); - $user->updateAvatar(); - } - - /** - * tests whether an avatar can be retrieved from LDAP and stored correctly - * - * @return bool - */ - protected function case1() { - $image = file_get_contents(__DIR__ . '/../../data/avatar-valid.jpg'); - $dn = 'uid=alice,ou=Users,' . $this->base; - $username = 'alice1337'; - - $this->execFetchTest($dn, $username, $image); - - return \OC::$server->getAvatarManager()->getAvatar($username)->exists(); - } - - /** - * tests whether an image received from LDAP which is of an invalid file - * type is dealt with properly (i.e. not set and not dying). - * - * @return bool - */ - protected function case2() { - // gif by Pmspinner from https://commons.wikimedia.org/wiki/File:Avatar2469_3.gif - $image = file_get_contents(__DIR__ . '/../../data/avatar-invalid.gif'); - $dn = 'uid=boris,ou=Users,' . $this->base; - $username = 'boris7844'; - - $this->execFetchTest($dn, $username, $image); - - return !\OC::$server->getAvatarManager()->getAvatar($username)->exists(); - } - - /** - * This writes an image to the 'jpegPhoto' attribute on LDAP. - * - * @param string $dn - * @param string $image An image read via file_get_contents - * @throws \OC\ServerNotAvailableException - */ - private function setJpegPhotoAttribute($dn, $image) { - $changeSet = ['jpegphoto' => $image]; - ldap_mod_add($this->connection->getConnectionResource(), $dn, $changeSet); - } - - protected function initUserManager() { - $this->userManager = new Manager( - \OC::$server->getConfig(), - new FilesystemHelper(), - new LogWrapper(), - \OC::$server->getAvatarManager(), - new Image(), - \OC::$server->getDatabaseConnection(), - \OC::$server->getUserManager(), - \OC::$server->getNotificationManager() - ); - } - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - parent::initConnection(); - $this->connection->setConfiguration([ - 'ldapUserFilter' => 'objectclass=inetOrgPerson', - 'ldapUserDisplayName' => 'displayName', - 'ldapGroupDisplayName' => 'cn', - 'ldapLoginFilter' => 'uid=%uid', - ]); - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestUserAvatar($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php deleted file mode 100644 index c48f51368bc6f..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserCleanUp.php +++ /dev/null @@ -1,105 +0,0 @@ - - * @author Christoph Wurst - * @author Morris Jobke - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib\User; - -use OCA\User_LDAP\Jobs\CleanUp; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\UserPluginManager; - -require_once __DIR__ . '/../../Bootstrap.php'; - -class IntegrationTestUserCleanUp extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php'); - parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); - $this->mapping->clear(); - $this->access->setUserMapper($this->mapping); - - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query(UserPluginManager::class)); - \OC_User::useBackend($userBackend); - } - - /** - * adds a map entry for the user, so we know the username - * - * @param $dn - * @param $username - */ - private function prepareUser($dn, $username) { - // assigns our self-picked oc username to the dn - $this->mapping->map($dn, $username, 'fakeUUID-' . $username); - } - - private function deleteUserFromLDAP($dn) { - $cr = $this->connection->getConnectionResource(); - ldap_delete($cr, $dn); - } - - /** - * tests whether a display name consisting of two parts is created correctly - * - * @return bool - */ - protected function case1() { - $username = 'alice1337'; - $dn = 'uid=alice,ou=Users,' . $this->base; - $this->prepareUser($dn, $username); - - $this->deleteUserFromLDAP($dn); - - $job = new CleanUp(); - $job->run([]); - - // user instance must not be requested from global user manager, before - // it is deleted from the LDAP server. The instance will be returned - // from cache and may false-positively confirm the correctness. - $user = \OC::$server->getUserManager()->get($username); - if ($user === null) { - return false; - } - $user->delete(); - - return null === \OC::$server->getUserManager()->get($username); - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestUserCleanUp($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php b/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php deleted file mode 100644 index a5712b164d1a3..0000000000000 --- a/apps/user_ldap/tests/Integration/Lib/User/IntegrationTestUserDisplayName.php +++ /dev/null @@ -1,113 +0,0 @@ - - * @author Joas Schilling - * @author Morris Jobke - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Integration\Lib\User; - -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Tests\Integration\AbstractIntegrationTest; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\UserPluginManager; - -require_once __DIR__ . '/../../Bootstrap.php'; - -class IntegrationTestUserDisplayName extends AbstractIntegrationTest { - /** @var UserMapping */ - protected $mapping; - - /** - * prepares the LDAP environment and sets up a test configuration for - * the LDAP backend. - */ - public function init() { - require(__DIR__ . '/../../setup-scripts/createExplicitUsers.php'); - parent::init(); - $this->mapping = new UserMapping(\OC::$server->getDatabaseConnection()); - $this->mapping->clear(); - $this->access->setUserMapper($this->mapping); - $userBackend = new User_LDAP($this->access, \OC::$server->getConfig(), \OC::$server->getNotificationManager(), \OC::$server->getUserSession(), \OC::$server->query(UserPluginManager::class)); - \OC_User::useBackend($userBackend); - } - - /** - * adds a map entry for the user, so we know the username - * - * @param $dn - * @param $username - */ - private function prepareUser($dn, $username) { - // assigns our self-picked oc username to the dn - $this->mapping->map($dn, $username, 'fakeUUID-' . $username); - } - - /** - * tests whether a display name consisting of two parts is created correctly - * - * @return bool - */ - protected function case1() { - $username = 'alice1337'; - $dn = 'uid=alice,ou=Users,' . $this->base; - $this->prepareUser($dn, $username); - $displayName = \OC::$server->getUserManager()->get($username)->getDisplayName(); - - return strpos($displayName, '(Alice@example.com)') !== false; - } - - /** - * tests whether a display name consisting of one part is created correctly - * - * @return bool - */ - protected function case2() { - $this->connection->setConfiguration([ - 'ldapUserDisplayName2' => '', - ]); - $username = 'boris23421'; - $dn = 'uid=boris,ou=Users,' . $this->base; - $this->prepareUser($dn, $username); - $displayName = \OC::$server->getUserManager()->get($username)->getDisplayName(); - - return strpos($displayName, '(Boris@example.com)') === false; - } - - /** - * sets up the LDAP configuration to be used for the test - */ - protected function initConnection() { - parent::initConnection(); - $this->connection->setConfiguration([ - 'ldapUserDisplayName' => 'displayName', - 'ldapUserDisplayName2' => 'mail', - ]); - } -} - -/** @var string $host */ -/** @var int $port */ -/** @var string $adn */ -/** @var string $apwd */ -/** @var string $bdn */ -$test = new IntegrationTestUserDisplayName($host, $port, $adn, $apwd, $bdn); -$test->init(); -$test->run(); diff --git a/apps/user_ldap/tests/Integration/data/avatar-invalid.gif b/apps/user_ldap/tests/Integration/data/avatar-invalid.gif deleted file mode 100644 index 000108834d8ef..0000000000000 Binary files a/apps/user_ldap/tests/Integration/data/avatar-invalid.gif and /dev/null differ diff --git a/apps/user_ldap/tests/Integration/data/avatar-valid.jpg b/apps/user_ldap/tests/Integration/data/avatar-valid.jpg deleted file mode 100644 index 451b631eea6dd..0000000000000 Binary files a/apps/user_ldap/tests/Integration/data/avatar-valid.jpg and /dev/null differ diff --git a/apps/user_ldap/tests/Integration/readme.md b/apps/user_ldap/tests/Integration/readme.md deleted file mode 100644 index e20efef8fdc69..0000000000000 --- a/apps/user_ldap/tests/Integration/readme.md +++ /dev/null @@ -1,60 +0,0 @@ -# Requirements # - -Have (as in do copy if not already done) the following files from https://github.com/owncloud/administration/tree/master/ldap-testing copied into the directory "setup-scripts": - - * start.sh - * stop.sh - * config.php - -Configure config.php according to your needs, also have a look into the LDAP and network settings in start.sh and stop.sh. - -# Usage # - -The basic command to run a test is: - -```# ./run-test.sh [phpscript]``` - -Yes, run it as root from within this directory. - -Example: - -``` -$ sudo ./run-test.sh lib/IntegrationTestAccessGroupsMatchFilter.php -71cbe88a4993e67066714d71c1cecc5ef26a54911a208103cb6294f90459e574 -c74dc0155db4efa7a0515d419528a8727bbc7596601cf25b0df05e348bd74895 -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -c74dc0155db4 osixia/phpldapadmin:0.5.1 "/sbin/my_init" 1 seconds ago Up Less than a second 80/tcp, 0.0.0.0:8443->443/tcp docker-phpldapadmin -71cbe88a4993 nickstenning/slapd:latest "/sbin/my_init" 1 seconds ago Up Less than a second 127.0.0.1:7770->389/tcp docker-slapd - -LDAP server now available under 127.0.0.1:7770 (internal IP is 172.17.0.78) -phpldapadmin now available under https://127.0.0.1:8443 - -created user : Alice Ealic -created group : RedGroup -created group : BlueGroup -created group : GreenGroup -created group : PurpleGroup -running case1 -running case2 -Tests succeeded -Stopping and resetting containers -docker-slapd -docker-phpldapadmin -docker-slapd -docker-phpldapadmin -``` - -# How it works # - -1. start.sh is executed which brings up a fresh and clean OpenLDAP in Docker. -2. The provided test script is executed. It also outputs results. -3. stop.sh is executed to shut down OpenLDAP - -# Beware # - -This is quick solution for basically one test case. With expension this mechanism should be improved as well. - -It does not run automatically, unless you do it. No integration with any testing framework. - -exceptionOnLostConnection.php is not part of this mechanism. Read its source and run it isolated. While you're at it, port it :þ - diff --git a/apps/user_ldap/tests/Integration/run-all.sh b/apps/user_ldap/tests/Integration/run-all.sh deleted file mode 100755 index 02bab97e45fe1..0000000000000 --- a/apps/user_ldap/tests/Integration/run-all.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -trigger_notification() { - which notify-send 1>/dev/null - if [[ $? == 1 ]] ; then - return - fi - export NOTIFY_USER=$SUDO_USER - export RESULT_STR=$1 - # does not work. just pipe result into a non-sudo cmd - su "$NOTIFY_USER" -c "notify-send -u normal -t 43200000 -a Nextcloud -i Nextcloud \"LDAP Integration tests $RESULT_STR\"" -} - -FILES_ROOT=($(ls -d -p Lib/* | grep -v "/$")) -FILES_USER=($(ls -d -p Lib/User/* | grep -v "/$")) -# TODO: Loop through dirs (and subdirs?) once there are more -TESTFILES=("${FILES_ROOT[@]}" "${FILES_USER[@]}") - -TESTCMD="./run-test.sh" - -echo "Running " ${#TESTFILES[@]} " tests" -for TESTFILE in "${TESTFILES[@]}" ; do - echo -n "Test: $TESTFILE… " - STATE=`$TESTCMD "$TESTFILE" | grep -c "Tests succeeded"` - if [ "$STATE" -eq 0 ] ; then - echo "failed!" - trigger_notification "failed" - exit 1 - fi - echo "succeeded" -done - -echo -e "\nAll tests succeeded" -trigger_notification "succeeded" diff --git a/apps/user_ldap/tests/Integration/run-test.sh b/apps/user_ldap/tests/Integration/run-test.sh deleted file mode 100755 index 7a29db2567075..0000000000000 --- a/apps/user_ldap/tests/Integration/run-test.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -if [ $1 ] ; then - TESTSCRIPT=$1 -else - echo "No test file given" exit -fi - -if [ ! -e "$TESTSCRIPT" ] ; then - echo "Test file does not exist" - exit -fi - - -# sleep is necessary, otherwise the LDAP server cannot be connected to, yet. -setup-scripts/start.sh && sleep 5 && php -f "$TESTSCRIPT" -setup-scripts/stop.sh diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php deleted file mode 100644 index 69bc90dedb245..0000000000000 --- a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroups.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @author Christoph Wurst - * @author Morris Jobke - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -if (php_sapi_name() !== 'cli') { - print('Only via CLI, please.'); - exit(1); -} - -include __DIR__ . '/config.php'; - -$cr = ldap_connect($host, $port); -ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3); -$ok = ldap_bind($cr, $adn, $apwd); - -if (!$ok) { - die(ldap_error($cr)); -} - -$ouName = 'Groups'; -$ouDN = 'ou=' . $ouName . ',' . $bdn; - -//creates an OU -if (true) { - $entry = []; - $entry['objectclass'][] = 'top'; - $entry['objectclass'][] = 'organizationalunit'; - $entry['ou'] = $ouName; - $b = ldap_add($cr, $ouDN, $entry); - if (!$b) { - die(ldap_error($cr)); - } -} - -$groups = ['RedGroup', 'BlueGroup', 'GreenGroup', 'PurpleGroup']; -// groupOfNames requires groups to have at least one member -// the member used is created by createExplicitUsers.php script -$omniMember = 'uid=alice,ou=Users,' . $bdn; - -foreach ($groups as $cn) { - $newDN = 'cn=' . $cn . ',' . $ouDN; - - $entry = []; - $entry['cn'] = $cn; - $entry['objectclass'][] = 'groupOfNames'; - $entry['member'][] = $omniMember; - - $ok = ldap_add($cr, $newDN, $entry); - if ($ok) { - echo('created group ' . ': ' . $entry['cn'] . PHP_EOL); - } else { - die(ldap_error($cr)); - } -} diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php deleted file mode 100644 index e2607b0ccc39b..0000000000000 --- a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitGroupsDifferentOU.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @author Christoph Wurst - * @author Morris Jobke - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -if (php_sapi_name() !== 'cli') { - print('Only via CLI, please.'); - exit(1); -} - -include __DIR__ . '/config.php'; - -$cr = ldap_connect($host, $port); -ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3); -$ok = ldap_bind($cr, $adn, $apwd); - -if (!$ok) { - die(ldap_error($cr)); -} - -$ouName = 'SpecialGroups'; -$ouDN = 'ou=' . $ouName . ',' . $bdn; - -//creates an OU -if (true) { - $entry = []; - $entry['objectclass'][] = 'top'; - $entry['objectclass'][] = 'organizationalunit'; - $entry['ou'] = $ouName; - $b = ldap_add($cr, $ouDN, $entry); - if (!$b) { - die(ldap_error($cr)); - } -} - -$groups = ['SquareGroup', 'CircleGroup', 'TriangleGroup', 'SquaredCircleGroup']; -// groupOfNames requires groups to have at least one member -// the member used is created by createExplicitUsers.php script -$omniMember = 'uid=alice,ou=Users,' . $bdn; - -foreach ($groups as $cn) { - $newDN = 'cn=' . $cn . ',' . $ouDN; - - $entry = []; - $entry['cn'] = $cn; - $entry['objectclass'][] = 'groupOfNames'; - $entry['member'][] = $omniMember; - - $ok = ldap_add($cr, $newDN, $entry); - if ($ok) { - echo('created group ' . ': ' . $entry['cn'] . PHP_EOL); - } else { - die(ldap_error($cr)); - } -} diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php b/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php deleted file mode 100644 index 6160179b9d46b..0000000000000 --- a/apps/user_ldap/tests/Integration/setup-scripts/createExplicitUsers.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @author Christoph Wurst - * @author Morris Jobke - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -if (php_sapi_name() !== 'cli') { - print('Only via CLI, please.'); - exit(1); -} - -include __DIR__ . '/config.php'; - -$cr = ldap_connect($host, $port); -ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3); -$ok = ldap_bind($cr, $adn, $apwd); - -if (!$ok) { - die(ldap_error($cr)); -} - -$ouName = 'Users'; -$ouDN = 'ou=' . $ouName . ',' . $bdn; - -//creates on OU -if (true) { - $entry = []; - $entry['objectclass'][] = 'top'; - $entry['objectclass'][] = 'organizationalunit'; - $entry['ou'] = $ouName; - $b = ldap_add($cr, $ouDN, $entry); - if (!$b) { - die(ldap_error($cr)); - } -} - -$users = ['alice', 'boris', 'cynthia', 'derek', 'evelina', 'fatima', 'gregor']; - -foreach ($users as $uid) { - $newDN = 'uid=' . $uid . ',' . $ouDN; - $fn = ucfirst($uid); - $sn = ucfirst(str_shuffle($uid)); // not so explicit but it's OK. - - $entry = []; - $entry['cn'] = $fn . ' ' . $sn; - $entry['objectclass'][] = 'inetOrgPerson'; - $entry['objectclass'][] = 'person'; - $entry['sn'] = $sn; - $entry['userPassword'] = $uid; - $entry['displayName'] = $sn . ', ' . $fn; - $entry['mail'] = $fn . '@example.com'; - - $ok = ldap_add($cr, $newDN, $entry); - if ($ok) { - echo('created user ' . ': ' . $entry['cn'] . PHP_EOL); - } else { - die(ldap_error($cr)); - } -} diff --git a/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php b/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php deleted file mode 100644 index 5a36ce24838db..0000000000000 --- a/apps/user_ldap/tests/Integration/setup-scripts/createUsersWithoutDisplayName.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @author Christoph Wurst - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -if (php_sapi_name() !== 'cli') { - print('Only via CLI, please.'); - exit(1); -} - -include __DIR__ . '/config.php'; - -$cr = ldap_connect($host, $port); -ldap_set_option($cr, LDAP_OPT_PROTOCOL_VERSION, 3); -$ok = ldap_bind($cr, $adn, $apwd); - -if (!$ok) { - die(ldap_error($cr)); -} - -$ouName = 'Users'; -$ouDN = 'ou=' . $ouName . ',' . $bdn; - -$users = ['robot']; - -foreach ($users as $uid) { - $newDN = 'uid=' . $uid . ',' . $ouDN; - $fn = ucfirst($uid); - $sn = ucfirst(str_shuffle($uid)); // not so explicit but it's OK. - - $entry = []; - $entry['cn'] = ucfirst($uid); - $entry['objectclass'][] = 'inetOrgPerson'; - $entry['objectclass'][] = 'person'; - $entry['sn'] = $sn; - $entry['userPassword'] = $uid; - - $ok = ldap_add($cr, $newDN, $entry); - if ($ok) { - echo('created user ' . ': ' . $entry['cn'] . PHP_EOL); - } else { - die(ldap_error($cr)); - } -} diff --git a/apps/user_ldap/tests/Jobs/CleanUpTest.php b/apps/user_ldap/tests/Jobs/CleanUpTest.php deleted file mode 100644 index 73d246ac4e215..0000000000000 --- a/apps/user_ldap/tests/Jobs/CleanUpTest.php +++ /dev/null @@ -1,155 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Jobs; - -use OCA\User_LDAP\Helper; -use OCP\IConfig; -use OCP\IDBConnection; - -class CleanUpTest extends \Test\TestCase { - public function getMocks() { - $mocks = []; - $mocks['userBackend'] = - $this->getMockBuilder('\OCA\User_LDAP\User_Proxy') - ->disableOriginalConstructor() - ->getMock(); - $mocks['deletedUsersIndex'] = - $this->getMockBuilder('\OCA\User_LDAP\User\DeletedUsersIndex') - ->disableOriginalConstructor() - ->getMock(); - $mocks['ocConfig'] = $this->createMock(IConfig::class); - $mocks['db'] = $this->createMock(IDBConnection::class); - $mocks['helper'] = $this->createMock(Helper::class); - - return $mocks; - } - - /** - * clean up job must not run when there are disabled configurations - */ - public function test_runNotAllowedByDisabledConfigurations() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) - ->method('haveDisabledConfigurations') - ->willReturn(true); - - $args['ocConfig']->expects($this->never()) - ->method('getSystemValue'); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); - $this->assertSame(false, $result); - } - - /** - * clean up job must not run when LDAP Helper is broken i.e. - * returning unexpected results - */ - public function test_runNotAllowedByBrokenHelper() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) - ->method('haveDisabledConfigurations') - ->will($this->throwException(new \Exception())); - - $args['ocConfig']->expects($this->never()) - ->method('getSystemValue'); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); - $this->assertSame(false, $result); - } - - /** - * clean up job must not run when it is not enabled - */ - public function test_runNotAllowedBySysConfig() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) - ->method('haveDisabledConfigurations') - ->willReturn(false); - - $args['ocConfig']->expects($this->once()) - ->method('getSystemValue') - ->willReturn(false); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); - $this->assertSame(false, $result); - } - - /** - * clean up job is allowed to run - */ - public function test_runIsAllowed() { - $args = $this->getMocks(); - $args['helper']->expects($this->once()) - ->method('haveDisabledConfigurations') - ->willReturn(false); - - $args['ocConfig']->expects($this->once()) - ->method('getSystemValue') - ->willReturn(true); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isCleanUpAllowed(); - $this->assertSame(true, $result); - } - - /** - * check whether offset will be reset when it needs to - */ - public function test_OffsetResetIsNecessary() { - $args = $this->getMocks(); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize() - 1); - $this->assertSame(true, $result); - } - - /** - * make sure offset is not reset when it is not due - */ - public function test_OffsetResetIsNotNecessary() { - $args = $this->getMocks(); - - $bgJob = new \OCA\User_LDAP\Jobs\CleanUp(); - $bgJob->setArguments($args); - - $result = $bgJob->isOffsetResetNecessary($bgJob->getChunkSize()); - $this->assertSame(false, $result); - } -} diff --git a/apps/user_ldap/tests/Jobs/SyncTest.php b/apps/user_ldap/tests/Jobs/SyncTest.php deleted file mode 100644 index 71868dcc6172e..0000000000000 --- a/apps/user_ldap/tests/Jobs/SyncTest.php +++ /dev/null @@ -1,386 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\Jobs; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\AccessFactory; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\ConnectionFactory; -use OCA\User_LDAP\Helper; -use OCA\User_LDAP\Jobs\Sync; -use OCA\User_LDAP\LDAP; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User\Manager; -use OCP\IAvatarManager; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\IUserManager; -use OCP\Notification\IManager; -use Test\TestCase; - -class SyncTest extends TestCase { - - /** @var array */ - protected $arguments; - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ - protected $helper; - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ - protected $ldapWrapper; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ - protected $userManager; - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $mapper; - /** @var Sync */ - protected $sync; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $avatarManager; - /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ - protected $dbc; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $ncUserManager; - /** @var IManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $notificationManager; - /** @var ConnectionFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $connectionFactory; - /** @var AccessFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $accessFactory; - - protected function setUp(): void { - parent::setUp(); - - $this->helper = $this->createMock(Helper::class); - $this->ldapWrapper = $this->createMock(LDAP::class); - $this->userManager = $this->createMock(Manager::class); - $this->mapper = $this->createMock(UserMapping::class); - $this->config = $this->createMock(IConfig::class); - $this->avatarManager = $this->createMock(IAvatarManager::class); - $this->dbc = $this->createMock(IDBConnection::class); - $this->ncUserManager = $this->createMock(IUserManager::class); - $this->notificationManager = $this->createMock(IManager::class); - $this->connectionFactory = $this->createMock(ConnectionFactory::class); - $this->accessFactory = $this->createMock(AccessFactory::class); - - $this->arguments = [ - 'helper' => $this->helper, - 'ldapWrapper' => $this->ldapWrapper, - 'userManager' => $this->userManager, - 'mapper' => $this->mapper, - 'config' => $this->config, - 'avatarManager' => $this->avatarManager, - 'dbc' => $this->dbc, - 'ncUserManager' => $this->ncUserManager, - 'notificationManager' => $this->notificationManager, - 'connectionFactory' => $this->connectionFactory, - 'accessFactory' => $this->accessFactory, - ]; - - $this->sync = new Sync(); - } - - public function intervalDataProvider() { - return [ - [ - 0, 1000, 750 - ], - [ - 22, 0, 50 - ], - [ - 500, 500, 500 - ], - [ - 1357, 0, 0 - ], - [ - 421337, 2000, 3000 - ] - ]; - } - - /** - * @dataProvider intervalDataProvider - */ - public function testUpdateInterval($userCount, $pagingSize1, $pagingSize2) { - $this->config->expects($this->once()) - ->method('setAppValue') - ->with('user_ldap', 'background_sync_interval', $this->anything()) - ->willReturnCallback(function ($a, $k, $interval) { - $this->assertTrue($interval >= SYNC::MIN_INTERVAL); - $this->assertTrue($interval <= SYNC::MAX_INTERVAL); - return true; - }); - $this->config->expects($this->atLeastOnce()) - ->method('getAppKeys') - ->willReturn([ - 'blabla', - 'ldap_paging_size', - 's07blabla', - 'installed', - 's07ldap_paging_size' - ]); - $this->config->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnOnConsecutiveCalls($pagingSize1, $pagingSize2); - - $this->mapper->expects($this->atLeastOnce()) - ->method('count') - ->willReturn($userCount); - - $this->sync->setArgument($this->arguments); - $this->sync->updateInterval(); - } - - public function moreResultsProvider() { - return [ - [ 3, 3, true ], - [ 3, 5, true ], - [ 3, 2, false], - [ 0, 4, false], - [ null, 4, false] - ]; - } - - /** - * @dataProvider moreResultsProvider - */ - public function testMoreResults($pagingSize, $results, $expected) { - $connection = $this->createMock(Connection::class); - $this->connectionFactory->expects($this->any()) - ->method('get') - ->willReturn($connection); - $connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($pagingSize) { - if ($key === 'ldapPagingSize') { - return $pagingSize; - } - return null; - }); - - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ - $access = $this->createMock(Access::class); - $this->accessFactory->expects($this->any()) - ->method('get') - ->with($connection) - ->willReturn($access); - - $this->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - - $access->expects($this->once()) - ->method('fetchListOfUsers') - ->willReturn(array_pad([], $results, 'someUser')); - $access->expects($this->any()) - ->method('combineFilterWithAnd') - ->willReturn('pseudo=filter'); - $access->connection = $connection; - $access->userManager = $this->userManager; - - $this->sync->setArgument($this->arguments); - $hasMoreResults = $this->sync->runCycle(['prefix' => 's01', 'offset' => 100]); - $this->assertSame($expected, $hasMoreResults); - } - - public function cycleDataProvider() { - $lastCycle = ['prefix' => 's01', 'offset' => 1000]; - $lastCycle2 = ['prefix' => '', 'offset' => 1000]; - return [ - [ null, ['s01'], ['prefix' => 's01', 'offset' => 0] ], - [ null, [''], ['prefix' => '', 'offset' => 0] ], - [ $lastCycle, ['s01', 's02'], ['prefix' => 's02', 'offset' => 0] ], - [ $lastCycle, [''], ['prefix' => '', 'offset' => 0] ], - [ $lastCycle2, ['', 's01'], ['prefix' => 's01', 'offset' => 0] ], - [ $lastCycle, [], null ], - ]; - } - - /** - * @dataProvider cycleDataProvider - */ - public function testDetermineNextCycle($cycleData, $prefixes, $expectedCycle) { - $this->helper->expects($this->any()) - ->method('getServerConfigurationPrefixes') - ->with(true) - ->willReturn($prefixes); - - if (is_array($expectedCycle)) { - $this->config->expects($this->exactly(2)) - ->method('setAppValue') - ->withConsecutive( - ['user_ldap', 'background_sync_prefix', $expectedCycle['prefix']], - ['user_ldap', 'background_sync_offset', $expectedCycle['offset']] - ); - } else { - $this->config->expects($this->never()) - ->method('setAppValue'); - } - - $this->sync->setArgument($this->arguments); - $nextCycle = $this->sync->determineNextCycle($cycleData); - - if ($expectedCycle === null) { - $this->assertNull($nextCycle); - } else { - $this->assertSame($expectedCycle['prefix'], $nextCycle['prefix']); - $this->assertSame($expectedCycle['offset'], $nextCycle['offset']); - } - } - - public function testQualifiesToRun() { - $cycleData = ['prefix' => 's01']; - - $this->config->expects($this->exactly(2)) - ->method('getAppValue') - ->willReturnOnConsecutiveCalls(time() - 60*40, time() - 60*20); - - $this->sync->setArgument($this->arguments); - $this->assertTrue($this->sync->qualifiesToRun($cycleData)); - $this->assertFalse($this->sync->qualifiesToRun($cycleData)); - } - - public function runDataProvider() { - return [ - #0 - one LDAP server, reset - [[ - 'prefixes' => [''], - 'scheduledCycle' => ['prefix' => '', 'offset' => '4500'], - 'pagingSize' => 500, - 'usersThisCycle' => 0, - 'expectedNextCycle' => ['prefix' => '', 'offset' => '0'], - 'mappedUsers' => 123, - ]], - #1 - 2 LDAP servers, next prefix - [[ - 'prefixes' => ['', 's01'], - 'scheduledCycle' => ['prefix' => '', 'offset' => '4500'], - 'pagingSize' => 500, - 'usersThisCycle' => 0, - 'expectedNextCycle' => ['prefix' => 's01', 'offset' => '0'], - 'mappedUsers' => 123, - ]], - #2 - 2 LDAP servers, rotate prefix - [[ - 'prefixes' => ['', 's01'], - 'scheduledCycle' => ['prefix' => 's01', 'offset' => '4500'], - 'pagingSize' => 500, - 'usersThisCycle' => 0, - 'expectedNextCycle' => ['prefix' => '', 'offset' => '0'], - 'mappedUsers' => 123, - ]], - ]; - } - - /** - * @dataProvider runDataProvider - */ - public function testRun($runData) { - $this->config->expects($this->any()) - ->method('getAppValue') - ->willReturnCallback(function ($app, $key, $default) use ($runData) { - if ($app === 'core' && $key === 'backgroundjobs_mode') { - return 'cron'; - } - if ($app = 'user_ldap') { - // for getCycle() - if ($key === 'background_sync_prefix') { - return $runData['scheduledCycle']['prefix']; - } - if ($key === 'background_sync_offset') { - return $runData['scheduledCycle']['offset']; - } - // for qualifiesToRun() - if ($key === $runData['scheduledCycle']['prefix'] . '_lastChange') { - return time() - 60*40; - } - // for getMinPagingSize - if ($key === $runData['scheduledCycle']['prefix'] . 'ldap_paging_size') { - return $runData['pagingSize']; - } - } - - return $default; - }); - $this->config->expects($this->exactly(3)) - ->method('setAppValue') - ->withConsecutive( - ['user_ldap', 'background_sync_prefix', $runData['expectedNextCycle']['prefix']], - ['user_ldap', 'background_sync_offset', $runData['expectedNextCycle']['offset']], - ['user_ldap', 'background_sync_interval', $this->anything()] - ); - $this->config->expects($this->any()) - ->method('getAppKeys') - ->with('user_ldap') - ->willReturn([$runData['scheduledCycle']['prefix'] . 'ldap_paging_size']); - - $this->helper->expects($this->any()) - ->method('getServerConfigurationPrefixes') - ->with(true) - ->willReturn($runData['prefixes']); - - $connection = $this->createMock(Connection::class); - $this->connectionFactory->expects($this->any()) - ->method('get') - ->willReturn($connection); - $connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($runData) { - if ($key === 'ldapPagingSize') { - return $runData['pagingSize']; - } - return null; - }); - - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ - $access = $this->createMock(Access::class); - $this->accessFactory->expects($this->any()) - ->method('get') - ->with($connection) - ->willReturn($access); - - $this->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - - $access->expects($this->once()) - ->method('fetchListOfUsers') - ->willReturn(array_pad([], $runData['usersThisCycle'], 'someUser')); - $access->expects($this->any()) - ->method('combineFilterWithAnd') - ->willReturn('pseudo=filter'); - $access->connection = $connection; - $access->userManager = $this->userManager; - - $this->mapper->expects($this->any()) - ->method('count') - ->willReturn($runData['mappedUsers']); - - $this->sync->run($this->arguments); - } -} diff --git a/apps/user_ldap/tests/LDAPGroupPluginDummy.php b/apps/user_ldap/tests/LDAPGroupPluginDummy.php deleted file mode 100644 index 7ff5cd8ac69c6..0000000000000 --- a/apps/user_ldap/tests/LDAPGroupPluginDummy.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\ILDAPGroupPlugin; - -class LDAPGroupPluginDummy implements ILDAPGroupPlugin { - public function respondToActions() { - return null; - } - - public function createGroup($gid) { - return null; - } - - public function deleteGroup($gid) { - return null; - } - - public function addToGroup($uid, $gid) { - return null; - } - - public function removeFromGroup($uid, $gid) { - return null; - } - - public function countUsersInGroup($gid, $search = '') { - return null; - } - - public function getGroupDetails($gid) { - return null; - } -} diff --git a/apps/user_ldap/tests/LDAPProviderTest.php b/apps/user_ldap/tests/LDAPProviderTest.php deleted file mode 100644 index a8910c4a272b6..0000000000000 --- a/apps/user_ldap/tests/LDAPProviderTest.php +++ /dev/null @@ -1,699 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Julius Härtl - * @author Roeland Jago Douma - * @author root - * @author Vinicius Cubas Brand - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OC\User\Manager; -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\IGroupLDAP; -use OCA\User_LDAP\IUserLDAP; -use OCP\EventDispatcher\IEventDispatcher; -use OCP\IConfig; -use OCP\IServerContainer; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; - -/** - * Class LDAPProviderTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class LDAPProviderTest extends \Test\TestCase { - protected function setUp(): void { - parent::setUp(); - } - - private function getServerMock(IUserLDAP $userBackend, IGroupLDAP $groupBackend) { - $server = $this->getMockBuilder('OC\Server') - ->setMethods(['getUserManager', 'getBackends', 'getGroupManager']) - ->setConstructorArgs(['', new \OC\Config(\OC::$configDir)]) - ->getMock(); - $server->expects($this->at(1)) - ->method('getBackends') - ->willReturn([$userBackend]); - $server->expects($this->any()) - ->method('getUserManager') - ->willReturn($this->getUserManagerMock($userBackend)); - $server->expects($this->any()) - ->method('getGroupManager') - ->willReturn($this->getGroupManagerMock($groupBackend)); - $server->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - return $server; - } - - private function getUserManagerMock(IUserLDAP $userBackend) { - $userManager = $this->getMockBuilder(Manager::class) - ->setMethods(['getBackends']) - ->setConstructorArgs([ - $this->createMock(IConfig::class), - $this->createMock(EventDispatcherInterface::class), - $this->createMock(IEventDispatcher::class) - ]) - ->getMock(); - $userManager->expects($this->any()) - ->method('getBackends') - ->willReturn([$userBackend]); - return $userManager; - } - - private function getGroupManagerMock(IGroupLDAP $groupBackend) { - $groupManager = $this->getMockBuilder('OC\Group\Manager') - ->setMethods(['getBackends']) - ->disableOriginalConstructor() - ->getMock(); - $groupManager->expects($this->any()) - ->method('getBackends') - ->willReturn([$groupBackend]); - return $groupManager; - } - - private function getDefaultGroupBackendMock() { - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - return $groupBackend; - } - - private function getLDAPProvider(IServerContainer $serverContainer) { - $factory = new \OCA\User_LDAP\LDAPProviderFactory($serverContainer); - return $factory->getLDAPProvider(); - } - - - public function testGetUserDNUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getUserDN('nonexisting_user'); - } - - public function testGetUserDN() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(2)) - ->method('username2dn') - ->willReturn('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org', - $ldapProvider->getUserDN('existing_user')); - } - - - public function testGetGroupDNGroupIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getGroupDN('nonexisting_group'); - } - - public function testGetGroupDN() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'username2dn']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'groupname2dn']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->at(0)) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->at(2)) - ->method('groupname2dn') - ->willReturn('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org'); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('cn=existing_group,ou=Are Sufficient To,ou=Test,dc=example,dc=org', - $ldapProvider->getGroupDN('existing_group')); - } - - public function testGetUserName() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['dn2UserName']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('dn2UserName') - ->willReturn('existing_user'); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('existing_user', - $ldapProvider->getUserName('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - public function testDNasBaseParameter() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals( - $helper->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), - $ldapProvider->DNasBaseParameter('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - public function testSanitizeDN() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $helper = new \OCA\User_LDAP\Helper(\OC::$server->getConfig()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals( - $helper->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org'), - $ldapProvider->sanitizeDN('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - - public function testGetLDAPConnectionUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPConnection('nonexisting_user'); - } - - public function testGetLDAPConnection() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getNewLDAPConnection']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method('getNewLDAPConnection') - ->willReturn(true); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertTrue($ldapProvider->getLDAPConnection('existing_user')); - } - - - public function testGetGroupLDAPConnectionGroupIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getGroupLDAPConnection('nonexisting_group'); - } - - public function testGetGroupLDAPConnection() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists','getNewLDAPConnection']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any()) - ->method('groupExists') - ->willReturn(true); - - $groupBackend->expects($this->any()) - ->method('getNewLDAPConnection') - ->willReturn(true); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertTrue($ldapProvider->getGroupLDAPConnection('existing_group')); - } - - - public function testGetLDAPBaseUsersUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPBaseUsers('nonexisting_user'); - } - - public function testGetLDAPBaseUsers() { - $bases = [ - 'ou=users,ou=foobar,dc=example,dc=org', - 'ou=users,ou=barfoo,dc=example,dc=org', - ]; - $dn = 'uid=malik,' . $bases[1]; - - $connection = $this->createMock(Connection::class); - $connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($bases) { - switch ($key) { - case 'ldapBaseUsers': - return $bases; - } - return null; - }); - - $access = $this->createMock(Access::class); - $access->expects($this->any()) - ->method('getConnection') - ->willReturn($connection); - $access->expects($this->exactly(2)) - ->method('isDNPartOfBase') - ->willReturnOnConsecutiveCalls(false, true); - $access->expects($this->atLeastOnce()) - ->method('username2dn') - ->willReturn($dn); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->atLeastOnce()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method('getLDAPAccess') - ->willReturn($access); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals($bases[1], $ldapProvider->getLDAPBaseUsers('existing_user')); - } - - - public function testGetLDAPBaseGroupsUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPBaseGroups('nonexisting_user'); - } - - public function testGetLDAPBaseGroups() { - $bases = [ - 'ou=groupd,ou=foobar,dc=example,dc=org', - 'ou=groups,ou=barfoo,dc=example,dc=org', - ]; - - $connection = $this->createMock(Connection::class); - $connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($key) use ($bases) { - switch ($key) { - case 'ldapBaseGroups': - return $bases; - } - return null; - }); - - $access = $this->createMock(Access::class); - $access->expects($this->any()) - ->method('getConnection') - ->willReturn($connection); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method('getLDAPAccess') - ->willReturn($access); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals($bases[0], $ldapProvider->getLDAPBaseGroups('existing_user')); - } - - - public function testClearCacheUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearCache('nonexisting_user'); - } - - public function testClearCache() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'clearCache']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('clearCache') - ->willReturn(true); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearCache('existing_user'); - $this->addToAssertionCount(1); - } - - - public function testClearGroupCacheGroupIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearGroupCache('nonexisting_group'); - } - - public function testClearGroupCache() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'clearCache']) - ->disableOriginalConstructor() - ->getMock(); - $groupBackend->expects($this->at(0)) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->at(3)) - ->method('clearCache') - ->willReturn(true); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->clearGroupCache('existing_group'); - $this->addToAssertionCount(1); - } - - public function testDnExists() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['dn2UserName']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any()) - ->method('dn2UserName') - ->willReturn('existing_user'); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertTrue($ldapProvider->dnExists('cn=existing_user,ou=Are Sufficient To,ou=Test,dc=example,dc=org')); - } - - public function testFlagRecord() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->flagRecord('existing_user'); - $this->addToAssertionCount(1); - } - - public function testUnflagRecord() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods([]) - ->disableOriginalConstructor() - ->getMock(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->unflagRecord('existing_user'); - $this->addToAssertionCount(1); - } - - - public function testGetLDAPDisplayNameFieldUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPDisplayNameField('nonexisting_user'); - } - - public function testGetLDAPDisplayNameField() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('getConfiguration') - ->willReturn(['ldap_display_name'=>'displayName']); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('displayName', $ldapProvider->getLDAPDisplayNameField('existing_user')); - } - - - public function testGetLDAPEmailFieldUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('User id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->any())->method('userExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPEmailField('nonexisting_user'); - } - - public function testGetLDAPEmailField() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->setMethods(['userExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - $userBackend->expects($this->at(0)) - ->method('userExists') - ->willReturn(true); - $userBackend->expects($this->at(3)) - ->method('getConfiguration') - ->willReturn(['ldap_email_attr'=>'mail']); - $userBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $this->getDefaultGroupBackendMock()); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('mail', $ldapProvider->getLDAPEmailField('existing_user')); - } - - - public function testGetLDAPGroupMemberAssocUserIDNotFound() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Group id not found in LDAP'); - - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->any())->method('groupExists')->willReturn(false); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $ldapProvider->getLDAPGroupMemberAssoc('nonexisting_group'); - } - - public function testgetLDAPGroupMemberAssoc() { - $userBackend = $this->getMockBuilder('OCA\User_LDAP\User_LDAP') - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend = $this->getMockBuilder('OCA\User_LDAP\Group_LDAP') - ->setMethods(['groupExists', 'getLDAPAccess', 'getConnection', 'getConfiguration']) - ->disableOriginalConstructor() - ->getMock(); - - $groupBackend->expects($this->at(0)) - ->method('groupExists') - ->willReturn(true); - $groupBackend->expects($this->any()) - ->method('getConfiguration') - ->willReturn(['ldap_group_member_assoc_attribute'=>'assoc_type']); - $groupBackend->expects($this->any()) - ->method($this->anything()) - ->willReturnSelf(); - - $server = $this->getServerMock($userBackend, $groupBackend); - - $ldapProvider = $this->getLDAPProvider($server); - $this->assertEquals('assoc_type', $ldapProvider->getLDAPGroupMemberAssoc('existing_group')); - } -} diff --git a/apps/user_ldap/tests/LDAPTest.php b/apps/user_ldap/tests/LDAPTest.php deleted file mode 100644 index 443bafe505b43..0000000000000 --- a/apps/user_ldap/tests/LDAPTest.php +++ /dev/null @@ -1,96 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Lukas Reschke - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\LDAP; -use Test\TestCase; - -class LDAPTest extends TestCase { - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ - private $ldap; - - protected function setUp(): void { - parent::setUp(); - $this->ldap = $this->getMockBuilder(LDAP::class) - ->setMethods(['invokeLDAPMethod']) - ->getMock(); - } - - public function errorProvider() { - return [ - [ - 'ldap_search(): Partial search results returned: Sizelimit exceeded at /srv/http/nextcloud/master/apps/user_ldap/lib/LDAP.php#292', - false - ], - [ - 'Some other error', true - ] - ]; - } - - /** - * @param string $errorMessage - * @param bool $passThrough - * @dataProvider errorProvider - */ - public function testSearchWithErrorHandler(string $errorMessage, bool $passThrough) { - $wasErrorHandlerCalled = false; - $errorHandler = function ($number, $message, $file, $line) use (&$wasErrorHandlerCalled) { - $wasErrorHandlerCalled = true; - }; - - set_error_handler($errorHandler); - - $this->ldap - ->expects($this->once()) - ->method('invokeLDAPMethod') - ->with('search', $this->anything(), $this->anything(), $this->anything(), $this->anything(), $this->anything()) - ->willReturnCallback(function () use ($errorMessage) { - trigger_error($errorMessage); - }); - - $fakeResource = ldap_connect(); - $this->ldap->search($fakeResource, 'base', 'filter', []); - $this->assertSame($wasErrorHandlerCalled, $passThrough); - - restore_error_handler(); - } - - public function testModReplace() { - $link = $this->createMock(LDAP::class); - $userDN = 'CN=user'; - $password = 'MyPassword'; - $this->ldap - ->expects($this->once()) - ->method('invokeLDAPMethod') - ->with('mod_replace', $link, $userDN, ['userPassword' => $password]) - ->willReturn(true); - - $this->assertTrue($this->ldap->modReplace($link, $userDN, $password)); - } -} diff --git a/apps/user_ldap/tests/LDAPUserPluginDummy.php b/apps/user_ldap/tests/LDAPUserPluginDummy.php deleted file mode 100644 index a3bcc252fbeae..0000000000000 --- a/apps/user_ldap/tests/LDAPUserPluginDummy.php +++ /dev/null @@ -1,60 +0,0 @@ - - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\ILDAPUserPlugin; - -class LDAPUserPluginDummy implements ILDAPUserPlugin { - public function respondToActions() { - return null; - } - - public function createUser($username, $password) { - return null; - } - - public function setPassword($uid, $password) { - return null; - } - - public function getHome($uid) { - return null; - } - - public function getDisplayName($uid) { - return null; - } - - public function setDisplayName($uid, $displayName) { - return null; - } - - public function canChangeAvatar($uid) { - return null; - } - - public function countUsers() { - return null; - } -} diff --git a/apps/user_ldap/tests/Mapping/AbstractMappingTest.php b/apps/user_ldap/tests/Mapping/AbstractMappingTest.php deleted file mode 100644 index e4c37aff7cd29..0000000000000 --- a/apps/user_ldap/tests/Mapping/AbstractMappingTest.php +++ /dev/null @@ -1,303 +0,0 @@ - - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Stefan Weil - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Mapping; - -use OCA\User_LDAP\Mapping\AbstractMapping; -use OCP\IDBConnection; - -abstract class AbstractMappingTest extends \Test\TestCase { - abstract public function getMapper(\OCP\IDBConnection $dbMock); - - /** - * kiss test on isColNameValid - */ - public function testIsColNameValid() { - $dbMock = $this->createMock(IDBConnection::class); - $mapper = $this->getMapper($dbMock); - - $this->assertTrue($mapper->isColNameValid('ldap_dn')); - $this->assertFalse($mapper->isColNameValid('foobar')); - } - - /** - * returns an array of test entries with dn, name and uuid as keys - * @return array - */ - protected function getTestData() { - $data = [ - [ - 'dn' => 'uid=foobar,dc=example,dc=org', - 'name' => 'Foobar', - 'uuid' => '1111-AAAA-1234-CDEF', - ], - [ - 'dn' => 'uid=barfoo,dc=example,dc=org', - 'name' => 'Barfoo', - 'uuid' => '2222-BBBB-1234-CDEF', - ], - [ - 'dn' => 'uid=barabara,dc=example,dc=org', - 'name' => 'BaraBara', - 'uuid' => '3333-CCCC-1234-CDEF', - ] - ]; - - return $data; - } - - /** - * calls map() on the given mapper and asserts result for true - * @param \OCA\User_LDAP\Mapping\AbstractMapping $mapper - * @param array $data - */ - protected function mapEntries($mapper, $data) { - foreach ($data as $entry) { - $done = $mapper->map($entry['dn'], $entry['name'], $entry['uuid']); - $this->assertTrue($done); - } - } - - /** - * initalizes environment for a test run and returns an array with - * test objects. Preparing environment means that all mappings are cleared - * first and then filled with test entries. - * @return array 0 = \OCA\User_LDAP\Mapping\AbstractMapping, 1 = array of - * users or groups - */ - private function initTest() { - $dbc = \OC::$server->getDatabaseConnection(); - $mapper = $this->getMapper($dbc); - $data = $this->getTestData(); - // make sure DB is pristine, then fill it with test entries - $mapper->clear(); - $this->mapEntries($mapper, $data); - - return [$mapper, $data]; - } - - /** - * tests map() method with input that should result in not-mapping. - * Hint: successful mapping is tested inherently with mapEntries(). - */ - public function testMap() { - list($mapper, $data) = $this->initTest(); - - // test that mapping will not happen when it shall not - $tooLongDN = 'uid=joann,ou=Secret Small Specialized Department,ou=Some Tremendously Important Department,ou=Another Very Important Department,ou=Pretty Meaningful Derpartment,ou=Quite Broad And General Department,ou=The Topmost Department,dc=hugelysuccessfulcompany,dc=com'; - $paramKeys = ['', 'dn', 'name', 'uuid', $tooLongDN]; - foreach ($paramKeys as $key) { - $failEntry = $data[0]; - if (!empty($key)) { - $failEntry[$key] = 'do-not-get-mapped'; - } - $isMapped = $mapper->map($failEntry['dn'], $failEntry['name'], $failEntry['uuid']); - $this->assertFalse($isMapped); - } - } - - /** - * tests unmap() for both successful and unsuccessful removing of - * mapping entries - */ - public function testUnmap() { - list($mapper, $data) = $this->initTest(); - - foreach ($data as $entry) { - $result = $mapper->unmap($entry['name']); - $this->assertTrue($result); - } - - $result = $mapper->unmap('notAnEntry'); - $this->assertFalse($result); - } - - /** - * tests getDNByName(), getNameByDN() and getNameByUUID() for successful - * and unsuccessful requests. - */ - public function testGetMethods() { - list($mapper, $data) = $this->initTest(); - - foreach ($data as $entry) { - $fdn = $mapper->getDNByName($entry['name']); - $this->assertSame($fdn, $entry['dn']); - } - $fdn = $mapper->getDNByName('nosuchname'); - $this->assertFalse($fdn); - - foreach ($data as $entry) { - $name = $mapper->getNameByDN($entry['dn']); - $this->assertSame($name, $entry['name']); - } - $name = $mapper->getNameByDN('nosuchdn'); - $this->assertFalse($name); - - foreach ($data as $entry) { - $name = $mapper->getNameByUUID($entry['uuid']); - $this->assertSame($name, $entry['name']); - } - $name = $mapper->getNameByUUID('nosuchuuid'); - $this->assertFalse($name); - } - - /** - * tests getNamesBySearch() for successful and unsuccessful requests. - */ - public function testSearch() { - list($mapper,) = $this->initTest(); - - $names = $mapper->getNamesBySearch('oo', '%', '%'); - $this->assertTrue(is_array($names)); - $this->assertSame(2, count($names)); - $this->assertTrue(in_array('Foobar', $names)); - $this->assertTrue(in_array('Barfoo', $names)); - $names = $mapper->getNamesBySearch('nada'); - $this->assertTrue(is_array($names)); - $this->assertSame(0, count($names)); - } - - /** - * tests setDNbyUUID() for successful and unsuccessful update. - */ - public function testSetDNMethod() { - list($mapper, $data) = $this->initTest(); - - $newDN = 'uid=modified,dc=example,dc=org'; - $done = $mapper->setDNbyUUID($newDN, $data[0]['uuid']); - $this->assertTrue($done); - $fdn = $mapper->getDNByName($data[0]['name']); - $this->assertSame($fdn, $newDN); - - $newDN = 'uid=notme,dc=example,dc=org'; - $done = $mapper->setDNbyUUID($newDN, 'iamnothere'); - $this->assertFalse($done); - $name = $mapper->getNameByDN($newDN); - $this->assertFalse($name); - } - - /** - * tests setUUIDbyDN() for successful and unsuccessful update. - */ - public function testSetUUIDMethod() { - /** @var AbstractMapping $mapper */ - list($mapper, $data) = $this->initTest(); - - $newUUID = 'ABC737-DEF754'; - - $done = $mapper->setUUIDbyDN($newUUID, 'uid=notme,dc=example,dc=org'); - $this->assertFalse($done); - $name = $mapper->getNameByUUID($newUUID); - $this->assertFalse($name); - - $done = $mapper->setUUIDbyDN($newUUID, $data[0]['dn']); - $this->assertTrue($done); - $uuid = $mapper->getUUIDByDN($data[0]['dn']); - $this->assertSame($uuid, $newUUID); - } - - /** - * tests clear() for successful update. - */ - public function testClear() { - list($mapper, $data) = $this->initTest(); - - $done = $mapper->clear(); - $this->assertTrue($done); - foreach ($data as $entry) { - $name = $mapper->getNameByUUID($entry['uuid']); - $this->assertFalse($name); - } - } - - /** - * tests clear() for successful update. - */ - public function testClearCb() { - list($mapper, $data) = $this->initTest(); - - $callbackCalls = 0; - $test = $this; - - $callback = function (string $id) use ($test, &$callbackCalls) { - $test->assertTrue(trim($id) !== ''); - $callbackCalls++; - }; - - $done = $mapper->clearCb($callback, $callback); - $this->assertTrue($done); - $this->assertSame(count($data) * 2, $callbackCalls); - foreach ($data as $entry) { - $name = $mapper->getNameByUUID($entry['uuid']); - $this->assertFalse($name); - } - } - - /** - * tests getList() method - */ - public function testList() { - list($mapper, $data) = $this->initTest(); - - // get all entries without specifying offset or limit - $results = $mapper->getList(); - $this->assertSame(3, count($results)); - - // get all-1 entries by specifying offset, and an high limit - // specifying only offset without limit will not work by underlying lib - $results = $mapper->getList(1, 999); - $this->assertSame(count($data) - 1, count($results)); - - // get first 2 entries by limit, but not offset - $results = $mapper->getList(0, 2); - $this->assertSame(2, count($results)); - - // get 2nd entry by specifying both offset and limit - $results = $mapper->getList(1, 1); - $this->assertSame(1, count($results)); - } - - public function testGetListOfIdsByDn() { - /** @var AbstractMapping $mapper */ - list($mapper,) = $this->initTest(); - - $listOfDNs = []; - for ($i = 0; $i < 66640; $i++) { - // Postgres has a limit of 65535 values in a single IN list - $name = 'as_' . $i; - $dn = 'uid=' . $name . ',dc=example,dc=org'; - $listOfDNs[] = $dn; - if ($i % 20 === 0) { - $mapper->map($dn, $name, 'fake-uuid-' . $i); - } - } - - $result = $mapper->getListOfIdsByDn($listOfDNs); - $this->assertSame(66640 / 20, count($result)); - } -} diff --git a/apps/user_ldap/tests/Mapping/GroupMappingTest.php b/apps/user_ldap/tests/Mapping/GroupMappingTest.php deleted file mode 100644 index 6549ae66671ac..0000000000000 --- a/apps/user_ldap/tests/Mapping/GroupMappingTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @author Joas Schilling - * @author Morris Jobke - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Mapping; - -use OCA\User_LDAP\Mapping\GroupMapping; - -/** - * Class GroupMappingTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests\Mapping - */ -class GroupMappingTest extends AbstractMappingTest { - public function getMapper(\OCP\IDBConnection $dbMock) { - return new GroupMapping($dbMock); - } -} diff --git a/apps/user_ldap/tests/Mapping/UserMappingTest.php b/apps/user_ldap/tests/Mapping/UserMappingTest.php deleted file mode 100644 index 2417eda0b8cb6..0000000000000 --- a/apps/user_ldap/tests/Mapping/UserMappingTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @author Joas Schilling - * @author Morris Jobke - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\Mapping; - -use OCA\User_LDAP\Mapping\UserMapping; - -/** - * Class UserMappingTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests\Mapping - */ -class UserMappingTest extends AbstractMappingTest { - public function getMapper(\OCP\IDBConnection $dbMock) { - return new UserMapping($dbMock); - } -} diff --git a/apps/user_ldap/tests/Migration/AbstractUUIDFixTest.php b/apps/user_ldap/tests/Migration/AbstractUUIDFixTest.php deleted file mode 100644 index ec484dfe7eb27..0000000000000 --- a/apps/user_ldap/tests/Migration/AbstractUUIDFixTest.php +++ /dev/null @@ -1,198 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\Migration; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Helper; -use OCA\User_LDAP\LDAP; -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Migration\UUIDFixUser; -use OCA\User_LDAP\User_Proxy; -use OCP\IConfig; -use Test\TestCase; - -abstract class AbstractUUIDFixTest extends TestCase { - /** @var Helper|\PHPUnit\Framework\MockObject\MockObject */ - protected $helper; - - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - - /** @var LDAP|\PHPUnit\Framework\MockObject\MockObject */ - protected $ldap; - - /** @var UserMapping|GroupMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $mapper; - - /** @var UUIDFixUser */ - protected $job; - - /** @var User_Proxy|\PHPUnit\Framework\MockObject\MockObject */ - protected $proxy; - - /** @var Access|\PHPUnit\Framework\MockObject\MockObject */ - protected $access; - - /** @var bool */ - protected $isUser = true; - - protected function setUp(): void { - parent::setUp(); - - $this->ldap = $this->createMock(LDAP::class); - $this->config = $this->createMock(IConfig::class); - $this->access = $this->createMock(Access::class); - - $this->helper = $this->createMock(Helper::class); - $this->helper->expects($this->any()) - ->method('getServerConfigurationPrefixes') - ->with(true) - ->willReturn(['s01', 's03']); - } - - protected function mockProxy($className) { - $this->proxy = $this->createMock($className); - $this->proxy->expects($this->any()) - ->method('getLDAPAccess') - ->willReturn($this->access); - } - - protected function instantiateJob($className) { - $this->job = new $className($this->mapper, $this->ldap, $this->config, $this->helper); - $this->job->overrideProxy($this->proxy); - } - - public function testRunSingleRecord() { - $args = [ - 'records' => [ - 0 => [ - 'name' => 'Someone', - 'dn' => 'uid=Someone,dc=Somewhere', - 'uuid' => 'kaput' - ] - ] - ]; - $correctUUID = '4355-AED3-9D73-03AD'; - - $this->access->expects($this->once()) - ->method('getUUID') - ->with($args['records'][0]['dn'], $this->isUser) - ->willReturn($correctUUID); - - $this->mapper->expects($this->once()) - ->method('setUUIDbyDN') - ->with($correctUUID, $args['records'][0]['dn']); - - $this->job->run($args); - } - - public function testRunValidRecord() { - $correctUUID = '4355-AED3-9D73-03AD'; - $args = [ - 'records' => [ - 0 => [ - 'name' => 'Someone', - 'dn' => 'uid=Someone,dc=Somewhere', - 'uuid' => $correctUUID - ] - ] - ]; - - $this->access->expects($this->once()) - ->method('getUUID') - ->with($args['records'][0]['dn'], $this->isUser) - ->willReturn($correctUUID); - - $this->mapper->expects($this->never()) - ->method('setUUIDbyDN'); - - $this->job->run($args); - } - - public function testRunRemovedRecord() { - $args = [ - 'records' => [ - 0 => [ - 'name' => 'Someone', - 'dn' => 'uid=Someone,dc=Somewhere', - 'uuid' => 'kaput' - ] - ] - ]; - - $this->access->expects($this->once()) - ->method('getUUID') - ->with($args['records'][0]['dn'], $this->isUser) - ->willReturn(false); - - $this->mapper->expects($this->never()) - ->method('setUUIDbyDN'); - - $this->job->run($args); - } - - public function testRunManyRecords() { - $args = [ - 'records' => [ - 0 => [ - 'name' => 'Someone', - 'dn' => 'uid=Someone,dc=Somewhere', - 'uuid' => 'kaput' - ], - 1 => [ - 'name' => 'kdslkdsaIdsal', - 'dn' => 'uid=kdslkdsaIdsal,dc=Somewhere', - 'uuid' => 'AED3-4355-03AD-9D73' - ], - 2 => [ - 'name' => 'Paperboy', - 'dn' => 'uid=Paperboy,dc=Somewhere', - 'uuid' => 'kaput' - ] - ] - ]; - $correctUUIDs = ['4355-AED3-9D73-03AD', 'AED3-4355-03AD-9D73', 'AED3-9D73-4355-03AD']; - - $this->access->expects($this->exactly(3)) - ->method('getUUID') - ->withConsecutive( - [$args['records'][0]['dn'], $this->isUser], - [$args['records'][1]['dn'], $this->isUser], - [$args['records'][2]['dn'], $this->isUser] - ) - ->willReturnOnConsecutiveCalls($correctUUIDs[0], $correctUUIDs[1], $correctUUIDs[2]); - - $this->mapper->expects($this->exactly(2)) - ->method('setUUIDbyDN') - ->withConsecutive( - [$correctUUIDs[0], $args['records'][0]['dn']], - [$correctUUIDs[2], $args['records'][2]['dn']] - ); - - $this->job->run($args); - } -} diff --git a/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php b/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php deleted file mode 100644 index a1f04d44670ed..0000000000000 --- a/apps/user_ldap/tests/Migration/UUIDFixGroupTest.php +++ /dev/null @@ -1,50 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\Group_LDAP\Tests\Migration; - -use OCA\User_LDAP\Group_Proxy; -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\Migration\UUIDFixGroup; -use OCA\User_LDAP\Tests\Migration\AbstractUUIDFixTest; - -/** - * Class UUIDFixGroupTest - * - * @package OCA\Group_LDAP\Tests\Migration - * @group DB - */ -class UUIDFixGroupTest extends AbstractUUIDFixTest { - protected function setUp(): void { - $this->isUser = false; - parent::setUp(); - - $this->isUser = false; - - $this->mapper = $this->createMock(GroupMapping::class); - - $this->mockProxy(Group_Proxy::class); - $this->instantiateJob(UUIDFixGroup::class); - } -} diff --git a/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php b/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php deleted file mode 100644 index 492f0c657ac10..0000000000000 --- a/apps/user_ldap/tests/Migration/UUIDFixInsertTest.php +++ /dev/null @@ -1,197 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\Migration; - -use OCA\User_LDAP\Mapping\GroupMapping; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Migration\UUIDFixInsert; -use OCP\BackgroundJob\IJobList; -use OCP\IConfig; -use OCP\Migration\IOutput; -use Test\TestCase; - -class UUIDFixInsertTest extends TestCase { - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $userMapper; - - /** @var GroupMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $groupMapper; - - /** @var IJobList|\PHPUnit\Framework\MockObject\MockObject */ - protected $jobList; - - /** @var UUIDFixInsert */ - protected $job; - - protected function setUp(): void { - parent::setUp(); - - $this->jobList = $this->createMock(IJobList::class); - $this->config = $this->createMock(IConfig::class); - $this->userMapper = $this->createMock(UserMapping::class); - $this->groupMapper = $this->createMock(GroupMapping::class); - $this->job = new UUIDFixInsert( - $this->config, - $this->userMapper, - $this->groupMapper, - $this->jobList - ); - } - - public function testGetName() { - $this->assertSame('Insert UUIDFix background job for user and group in batches', $this->job->getName()); - } - - public function recordProvider() { - $record = [ - 'dn' => 'cn=somerecord,dc=somewhere', - 'name' => 'Something', - 'uuid' => 'AB12-3456-CDEF7-8GH9' - ]; - array_fill(0, 50, $record); - - $userBatches = [ - 0 => array_fill(0, 50, $record), - 1 => array_fill(0, 50, $record), - 2 => array_fill(0, 13, $record), - ]; - - $groupBatches = [ - 0 => array_fill(0, 7, $record), - ]; - - return [ - ['userBatches' => $userBatches, 'groupBatches' => $groupBatches] - ]; - } - - public function recordProviderTooLongAndNone() { - $record = [ - 'dn' => 'cn=somerecord,dc=somewhere', - 'name' => 'Something', - 'uuid' => 'AB12-3456-CDEF7-8GH9' - ]; - array_fill(0, 50, $record); - - $userBatches = [ - 0 => array_fill(0, 50, $record), - 1 => array_fill(0, 40, $record), - 2 => array_fill(0, 32, $record), - 3 => array_fill(0, 32, $record), - 4 => array_fill(0, 23, $record), - ]; - - $groupBatches = [0 => []]; - - return [ - ['userBatches' => $userBatches, 'groupBatches' => $groupBatches] - ]; - } - - /** - * @dataProvider recordProvider - */ - public function testRun($userBatches, $groupBatches) { - $this->config->expects($this->once()) - ->method('getAppValue') - ->with('user_ldap', 'installed_version', '1.2.1') - ->willReturn('1.2.0'); - - $this->userMapper->expects($this->exactly(3)) - ->method('getList') - ->withConsecutive([0, 50], [50, 50], [100, 50]) - ->willReturnOnConsecutiveCalls($userBatches[0], $userBatches[1], $userBatches[2]); - - $this->groupMapper->expects($this->exactly(1)) - ->method('getList') - ->with(0, 50) - ->willReturn($groupBatches[0]); - - $this->jobList->expects($this->exactly(4)) - ->method('add'); - - /** @var IOutput $out */ - $out = $this->createMock(IOutput::class); - $this->job->run($out); - } - - /** - * @dataProvider recordProviderTooLongAndNone - */ - public function testRunWithManyAndNone($userBatches, $groupBatches) { - $this->config->expects($this->once()) - ->method('getAppValue') - ->with('user_ldap', 'installed_version', '1.2.1') - ->willReturn('1.2.0'); - - $this->userMapper->expects($this->exactly(5)) - ->method('getList') - ->withConsecutive([0, 50], [0, 40], [0, 32], [32, 32], [64, 32]) - ->willReturnOnConsecutiveCalls($userBatches[0], $userBatches[1], $userBatches[2], $userBatches[3], $userBatches[4]); - - $this->groupMapper->expects($this->once()) - ->method('getList') - ->with(0, 50) - ->willReturn($groupBatches[0]); - - $this->jobList->expects($this->at(0)) - ->method('add') - ->willThrowException(new \InvalidArgumentException('Background job arguments can\'t exceed 4000 etc')); - $this->jobList->expects($this->at(1)) - ->method('add') - ->willThrowException(new \InvalidArgumentException('Background job arguments can\'t exceed 4000 etc')); - $this->jobList->expects($this->at(2)) - ->method('add'); - $this->jobList->expects($this->at(3)) - ->method('add'); - $this->jobList->expects($this->at(4)) - ->method('add'); - - /** @var IOutput $out */ - $out = $this->createMock(IOutput::class); - $this->job->run($out); - } - - public function testDonNotRun() { - $this->config->expects($this->once()) - ->method('getAppValue') - ->with('user_ldap', 'installed_version', '1.2.1') - ->willReturn('1.2.1'); - $this->userMapper->expects($this->never()) - ->method('getList'); - $this->groupMapper->expects($this->never()) - ->method('getList'); - $this->jobList->expects($this->never()) - ->method('add'); - - /** @var IOutput $out */ - $out = $this->createMock(IOutput::class); - $this->job->run($out); - } -} diff --git a/apps/user_ldap/tests/Migration/UUIDFixUserTest.php b/apps/user_ldap/tests/Migration/UUIDFixUserTest.php deleted file mode 100644 index 188c7b0f91db4..0000000000000 --- a/apps/user_ldap/tests/Migration/UUIDFixUserTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\Migration; - -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\Migration\UUIDFixUser; -use OCA\User_LDAP\User_Proxy; - -/** - * Class UUIDFixUserTest - * - * @package OCA\User_LDAP\Tests\Migration - * @group DB - */ -class UUIDFixUserTest extends AbstractUUIDFixTest { - protected function setUp(): void { - $this->isUser = true; - parent::setUp(); - - $this->mapper = $this->createMock(UserMapping::class); - - $this->mockProxy(User_Proxy::class); - $this->instantiateJob(UUIDFixUser::class); - } -} diff --git a/apps/user_ldap/tests/Settings/AdminTest.php b/apps/user_ldap/tests/Settings/AdminTest.php deleted file mode 100644 index 2599a966f06ed..0000000000000 --- a/apps/user_ldap/tests/Settings/AdminTest.php +++ /dev/null @@ -1,91 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Lukas Reschke - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\Settings; - -use OCA\User_LDAP\Configuration; -use OCA\User_LDAP\Settings\Admin; -use OCP\AppFramework\Http\TemplateResponse; -use OCP\IL10N; -use OCP\Template; -use Test\TestCase; - -/** - * @group DB - * @package OCA\User_LDAP\Tests\Settings - */ -class AdminTest extends TestCase { - /** @var Admin */ - private $admin; - /** @var IL10N */ - private $l10n; - - protected function setUp(): void { - parent::setUp(); - $this->l10n = $this->getMockBuilder(IL10N::class)->getMock(); - - $this->admin = new Admin( - $this->l10n - ); - } - - /** - * @UseDB - */ - public function testGetForm() { - $prefixes = ['s01']; - $hosts = ['s01' => '']; - - $wControls = new Template('user_ldap', 'part.wizardcontrols'); - $wControls = $wControls->fetchPage(); - $sControls = new Template('user_ldap', 'part.settingcontrols'); - $sControls = $sControls->fetchPage(); - - $parameters['serverConfigurationPrefixes'] = $prefixes; - $parameters['serverConfigurationHosts'] = $hosts; - $parameters['settingControls'] = $sControls; - $parameters['wizardControls'] = $wControls; - - // assign default values - $config = new Configuration('', false); - $defaults = $config->getDefaults(); - foreach ($defaults as $key => $default) { - $parameters[$key.'_default'] = $default; - } - - $expected = new TemplateResponse('user_ldap', 'settings', $parameters); - $this->assertEquals($expected, $this->admin->getForm()); - } - - public function testGetSection() { - $this->assertSame('ldap', $this->admin->getSection()); - } - - public function testGetPriority() { - $this->assertSame(5, $this->admin->getPriority()); - } -} diff --git a/apps/user_ldap/tests/Settings/SectionTest.php b/apps/user_ldap/tests/Settings/SectionTest.php deleted file mode 100644 index f27ac0843e82a..0000000000000 --- a/apps/user_ldap/tests/Settings/SectionTest.php +++ /dev/null @@ -1,79 +0,0 @@ - - * - * @author Joas Schilling - * @author Lukas Reschke - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\Settings; - -use OCA\User_LDAP\Settings\Section; -use OCP\IL10N; -use OCP\IURLGenerator; -use Test\TestCase; - -class SectionTest extends TestCase { - /** @var IURLGenerator|\PHPUnit\Framework\MockObject\MockObject */ - private $url; - /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ - private $l; - /** @var Section */ - private $section; - - protected function setUp(): void { - parent::setUp(); - $this->url = $this->createMock(IURLGenerator::class); - $this->l = $this->createMock(IL10N::class); - - $this->section = new Section( - $this->url, - $this->l - ); - } - - public function testGetID() { - $this->assertSame('ldap', $this->section->getID()); - } - - public function testGetName() { - $this->l - ->expects($this->once()) - ->method('t') - ->with('LDAP / AD integration') - ->willReturn('LDAP / AD integration'); - - $this->assertSame('LDAP / AD integration', $this->section->getName()); - } - - public function testGetPriority() { - $this->assertSame(25, $this->section->getPriority()); - } - - public function testGetIcon() { - $this->url->expects($this->once()) - ->method('imagePath') - ->with('user_ldap', 'app-dark.svg') - ->willReturn('icon'); - - $this->assertSame('icon', $this->section->getIcon()); - } -} diff --git a/apps/user_ldap/tests/User/DeletedUsersIndexTest.php b/apps/user_ldap/tests/User/DeletedUsersIndexTest.php deleted file mode 100644 index 77fdd31c173bb..0000000000000 --- a/apps/user_ldap/tests/User/DeletedUsersIndexTest.php +++ /dev/null @@ -1,122 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Morris Jobke - * @author Roeland Jago Douma - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\User; - -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User\DeletedUsersIndex; -use OCP\IConfig; -use OCP\IDBConnection; - -/** - * Class DeletedUsersIndexTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests\User - */ -class DeletedUsersIndexTest extends \Test\TestCase { - /** @var DeletedUsersIndex */ - protected $dui; - - /** @var IConfig */ - protected $config; - - /** @var IDBConnection */ - protected $db; - - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $mapping; - - protected function setUp(): void { - parent::setUp(); - - // no mocks for those as tests go against DB - $this->config = \OC::$server->getConfig(); - $this->db = \OC::$server->getDatabaseConnection(); - - // ensure a clean database - $this->config->deleteAppFromAllUsers('user_ldap'); - - $this->mapping = $this->createMock(UserMapping::class); - - $this->dui = new DeletedUsersIndex($this->config, $this->db, $this->mapping); - } - - protected function tearDown(): void { - $this->config->deleteAppFromAllUsers('user_ldap'); - parent::tearDown(); - } - - public function testMarkAndFetchUser() { - $uids = [ - 'cef3775c-71d2-48eb-8984-39a4051b0b95', - '8c4bbb40-33ed-42d0-9b14-85b0ab76c1cc', - ]; - - // ensure test works on a pristine state - $this->assertFalse($this->dui->hasUsers()); - - $this->dui->markUser($uids[0]); - - $this->assertTrue($this->dui->hasUsers()); - - $this->dui->markUser($uids[1]); - - $deletedUsers = $this->dui->getUsers(); - $this->assertSame(2, count($deletedUsers)); - - // ensure the different uids were used - foreach ($deletedUsers as $deletedUser) { - $this->assertTrue(in_array($deletedUser->getOCName(), $uids)); - $i = array_search($deletedUser->getOCName(), $uids); - $this->assertNotFalse($i); - unset($uids[$i]); - } - $this->assertEmpty($uids); - } - - public function testUnmarkUser() { - $uids = [ - '22a162c7-a9ee-487c-9f33-0563795583fb', - '1fb4e0da-4a75-47f3-8fa7-becc7e35c9c5', - ]; - - // we know this works, because of "testMarkAndFetchUser" - $this->dui->markUser($uids[0]); - // this returns a working instance of OfflineUser - $testUser = $this->dui->getUsers()[0]; - $testUser->unmark(); - - // the DUI caches the users, to clear mark someone else - $this->dui->markUser($uids[1]); - - $deletedUsers = $this->dui->getUsers(); - foreach ($deletedUsers as $deletedUser) { - $this->assertNotSame($testUser->getOCName(), $deletedUser->getOCName()); - } - } -} diff --git a/apps/user_ldap/tests/User/ManagerTest.php b/apps/user_ldap/tests/User/ManagerTest.php deleted file mode 100644 index 18499da9a8699..0000000000000 --- a/apps/user_ldap/tests/User/ManagerTest.php +++ /dev/null @@ -1,254 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Philippe Jung - * @author Roeland Jago Douma - * @author Roger Szabo - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\User; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\Manager; -use OCA\User_LDAP\User\User; -use OCP\IAvatarManager; -use OCP\IConfig; -use OCP\IDBConnection; -use OCP\Image; -use OCP\IUserManager; -use OCP\Notification\IManager as INotificationManager; - -/** - * Class Test_User_Manager - * - * @group DB - * - * @package OCA\User_LDAP\Tests\User - */ -class ManagerTest extends \Test\TestCase { - /** @var Access|\PHPUnit\Framework\MockObject\MockObject */ - protected $access; - - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - - /** @var FilesystemHelper|\PHPUnit\Framework\MockObject\MockObject */ - protected $fileSystemHelper; - - /** @var LogWrapper|\PHPUnit\Framework\MockObject\MockObject */ - protected $log; - - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $avatarManager; - - /** @var Image|\PHPUnit\Framework\MockObject\MockObject */ - protected $image; - - /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ - protected $dbc; - - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $ncUserManager; - - /** @var INotificationManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $notificationManager; - - /** @var ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject */ - protected $ldapWrapper; - - /** @var Connection */ - protected $connection; - - /** @var Manager */ - protected $manager; - - protected function setUp(): void { - parent::setUp(); - - $this->access = $this->createMock(Access::class); - $this->config = $this->createMock(IConfig::class); - $this->fileSystemHelper = $this->createMock(FilesystemHelper::class); - $this->log = $this->createMock(LogWrapper::class); - $this->avatarManager = $this->createMock(IAvatarManager::class); - $this->image = $this->createMock(Image::class); - $this->dbc = $this->createMock(IDBConnection::class); - $this->ncUserManager = $this->createMock(IUserManager::class); - $this->notificationManager = $this->createMock(INotificationManager::class); - - $this->ldapWrapper = $this->createMock(ILDAPWrapper::class); - $this->connection = new Connection($this->ldapWrapper, '', null); - - $this->access->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connection); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->manager = new Manager( - $this->config, - $this->fileSystemHelper, - $this->log, - $this->avatarManager, - $this->image, - $this->dbc, - $this->ncUserManager, - $this->notificationManager - ); - - $this->manager->setLdapAccess($this->access); - } - - public function dnProvider() { - return [ - ['cn=foo,dc=foobar,dc=bar'], - ['uid=foo,o=foobar,c=bar'], - ['ab=cde,f=ghei,mno=pq'], - ]; - } - - /** - * @dataProvider dnProvider - */ - public function testGetByDNExisting(string $inputDN) { - $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - - $this->access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($inputDN)) - ->willReturn(true); - $this->access->expects($this->once()) - ->method('dn2username') - ->with($this->equalTo($inputDN)) - ->willReturn($uid); - $this->access->expects($this->never()) - ->method('username2dn'); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->manager->get($inputDN); - - // Now we fetch the user again. If this leads to a failing test, - // runtime caching the manager is broken. - /** @noinspection PhpUnhandledExceptionInspection */ - $user = $this->manager->get($inputDN); - - $this->assertInstanceOf(User::class, $user); - } - - public function testGetByDNNotExisting() { - $inputDN = 'cn=gone,dc=foobar,dc=bar'; - - $this->access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($inputDN)) - ->willReturn(true); - $this->access->expects($this->once()) - ->method('dn2username') - ->with($this->equalTo($inputDN)) - ->willReturn(false); - $this->access->expects($this->once()) - ->method('username2dn') - ->with($this->equalTo($inputDN)) - ->willReturn(false); - - /** @noinspection PhpUnhandledExceptionInspection */ - $user = $this->manager->get($inputDN); - - $this->assertNull($user); - } - - public function testGetByUidExisting() { - $dn = 'cn=foo,dc=foobar,dc=bar'; - $uid = '563418fc-423b-1033-8d1c-ad5f418ee02e'; - - $this->access->expects($this->never()) - ->method('dn2username'); - $this->access->expects($this->once()) - ->method('username2dn') - ->with($this->equalTo($uid)) - ->willReturn($dn); - $this->access->expects($this->once()) - ->method('stringResemblesDN') - ->with($this->equalTo($uid)) - ->willReturn(false); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->manager->get($uid); - - // Now we fetch the user again. If this leads to a failing test, - // runtime caching the manager is broken. - /** @noinspection PhpUnhandledExceptionInspection */ - $user = $this->manager->get($uid); - - $this->assertInstanceOf(User::class, $user); - } - - public function testGetByUidNotExisting() { - $uid = 'gone'; - - $this->access->expects($this->never()) - ->method('dn2username'); - $this->access->expects($this->exactly(1)) - ->method('username2dn') - ->with($this->equalTo($uid)) - ->willReturn(false); - - /** @noinspection PhpUnhandledExceptionInspection */ - $user = $this->manager->get($uid); - - $this->assertNull($user); - } - - public function attributeRequestProvider() { - return [ - [false], - [true], - ]; - } - - /** - * @dataProvider attributeRequestProvider - */ - public function testGetAttributes($minimal) { - $this->connection->setConfiguration([ - 'ldapEmailAttribute' => 'MAIL', - 'ldapUserAvatarRule' => 'default', - 'ldapQuotaAttribute' => '', - 'ldapUserDisplayName2' => 'Mail', - ]); - - $attributes = $this->manager->getAttributes($minimal); - - $this->assertTrue(in_array('dn', $attributes)); - $this->assertTrue(in_array(strtolower($this->access->getConnection()->ldapEmailAttribute), $attributes)); - $this->assertTrue(!in_array($this->access->getConnection()->ldapEmailAttribute, $attributes)); #cases check - $this->assertFalse(in_array('', $attributes)); - $this->assertSame(!$minimal, in_array('jpegphoto', $attributes)); - $this->assertSame(!$minimal, in_array('thumbnailphoto', $attributes)); - $valueCounts = array_count_values($attributes); - $this->assertSame(1, $valueCounts['mail']); - } -} diff --git a/apps/user_ldap/tests/User/OfflineUserTest.php b/apps/user_ldap/tests/User/OfflineUserTest.php deleted file mode 100644 index 298e1708a58bc..0000000000000 --- a/apps/user_ldap/tests/User/OfflineUserTest.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * @author Arthur Schiwon - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests\User; - -use Doctrine\DBAL\Driver\Statement; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User\OfflineUser; -use OCP\IConfig; -use OCP\IDBConnection; -use Test\TestCase; - -class OfflineUserTest extends TestCase { - - /** @var OfflineUser */ - protected $offlineUser; - /** @var UserMapping|\PHPUnit\Framework\MockObject\MockObject */ - protected $mapping; - /** @var string */ - protected $uid; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ - protected $dbc; - - public function setUp(): void { - $this->uid = 'deborah'; - $this->config = $this->createMock(IConfig::class); - $this->dbc = $this->createMock(IDBConnection::class); - $this->mapping = $this->createMock(UserMapping::class); - - $this->offlineUser = new OfflineUser( - $this->uid, - $this->config, - $this->dbc, - $this->mapping - ); - } - - public function shareOwnerProvider(): array { - // tests for none, one, many - return [ - [ 0, 0, false], - [ 1, 0, true], - [ 0, 1, true], - [ 1, 1, true], - [ 2, 0, true], - [ 0, 2, true], - [ 2, 2, true], - ]; - } - - /** - * @dataProvider shareOwnerProvider - */ - public function testHasActiveShares(int $internalOwnerships, int $externalOwnerships, bool $expected) { - $queryMock = $this->createMock(Statement::class); - $queryMock->expects($this->atLeastOnce()) - ->method('execute'); - $queryMock->expects($this->atLeastOnce()) - ->method('rowCount') - ->willReturnOnConsecutiveCalls( - $internalOwnerships > 0 ? 1 : 0, - $externalOwnerships > 0 ? 1 : 0 - ); - - $this->dbc->expects($this->atLeastOnce()) - ->method('prepare') - ->willReturn($queryMock); - - $this->assertSame($expected, $this->offlineUser->getHasActiveShares()); - } -} diff --git a/apps/user_ldap/tests/User/UserTest.php b/apps/user_ldap/tests/User/UserTest.php deleted file mode 100644 index 25a896aee04ae..0000000000000 --- a/apps/user_ldap/tests/User/UserTest.php +++ /dev/null @@ -1,1230 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Juan Pablo Villafáñez - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Roger Szabo - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests\User; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\FilesystemHelper; -use OCA\User_LDAP\LogWrapper; -use OCA\User_LDAP\User\User; -use OCP\IAvatar; -use OCP\IAvatarManager; -use OCP\IConfig; -use OCP\Image; -use OCP\IUser; -use OCP\IUserManager; -use OCP\Notification\IManager as INotificationManager; -use OCP\Notification\INotification; - -/** - * Class UserTest - * - * @group DB - * - * @package OCA\User_LDAP\Tests\User - */ -class UserTest extends \Test\TestCase { - /** @var Access|\PHPUnit\Framework\MockObject\MockObject */ - protected $access; - /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */ - protected $connection; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - /** @var FilesystemHelper|\PHPUnit\Framework\MockObject\MockObject */ - protected $filesystemhelper; - /** @var INotificationManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $notificationManager; - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $userManager; - /** @var Image|\PHPUnit\Framework\MockObject\MockObject */ - protected $image; - /** @var IAvatarManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $avatarManager; - /** @var LogWrapper|\PHPUnit\Framework\MockObject\MockObject */ - protected $log; - /** @var string */ - protected $uid = 'alice'; - /** @var string */ - protected $dn = 'uid=alice,dc=foo,dc=bar'; - /** @var User */ - protected $user; - - protected function setUp(): void { - parent::setUp(); - - $this->connection = $this->createMock(Connection::class); - - $this->access = $this->createMock(Access::class); - $this->access->connection = $this->connection; - $this->access->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connection); - - $this->config = $this->createMock(IConfig::class); - $this->filesystemhelper = $this->createMock(FilesystemHelper::class); - $this->log = $this->createMock(LogWrapper::class); - $this->avatarManager = $this->createMock(IAvatarManager::class); - $this->image = $this->createMock(Image::class); - $this->userManager = $this->createMock(IUserManager::class); - $this->notificationManager = $this->createMock(INotificationManager::class); - - $this->user = new User( - $this->uid, - $this->dn, - $this->access, - $this->config, - $this->filesystemhelper, - $this->image, - $this->log, - $this->avatarManager, - $this->userManager, - $this->notificationManager - ); - } - - public function testGetDNandUsername() { - $this->assertSame($this->dn, $this->user->getDN()); - $this->assertSame($this->uid, $this->user->getUsername()); - } - - public function testUpdateEmailProvided() { - $this->connection->expects($this->once()) - ->method('__get') - ->with($this->equalTo('ldapEmailAttribute')) - ->willReturn('email'); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('email')) - ->willReturn(['alice@foo.bar']); - - $coreUser = $this->getMockBuilder(IUser::class) - ->disableOriginalConstructor() - ->getMock(); - $coreUser->expects($this->once()) - ->method('setEMailAddress') - ->with('alice@foo.bar'); - - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($coreUser); - - $this->user->updateEmail(); - } - - public function testUpdateEmailNotProvided() { - $this->connection->expects($this->once()) - ->method('__get') - ->with($this->equalTo('ldapEmailAttribute')) - ->willReturn('email'); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('email')) - ->willReturn(false); - - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->user->updateEmail(); - } - - public function testUpdateEmailNotConfigured() { - $this->connection->expects($this->once()) - ->method('__get') - ->with($this->equalTo('ldapEmailAttribute')) - ->willReturn(''); - - $this->access->expects($this->never()) - ->method('readAttribute'); - - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->user->updateEmail(); - } - - public function testUpdateQuotaAllProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', ''] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(['42 GB']); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->once()) - ->method('setQuota') - ->with('42 GB'); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->with($this->uid) - ->willReturn($coreUser); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaToDefaultAllProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', ''] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(['default']); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->once()) - ->method('setQuota') - ->with('default'); - - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->uid) - ->willReturn($coreUser); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaToNoneAllProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', ''] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(['none']); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->once()) - ->method('setQuota') - ->with('none'); - - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->uid) - ->willReturn($coreUser); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaDefaultProvided() { - $this->connection->expects($this->at(0)) - ->method('__get') - ->with($this->equalTo('ldapQuotaAttribute')) - ->willReturn('myquota'); - $this->connection->expects($this->at(1)) - ->method('__get') - ->with($this->equalTo('ldapQuotaDefault')) - ->willReturn('25 GB'); - $this->connection->expects($this->exactly(2)) - ->method('__get'); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(false); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->once()) - ->method('setQuota') - ->with('25 GB'); - - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->uid) - ->willReturn($coreUser); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaIndividualProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', ''] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(['27 GB']); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->once()) - ->method('setQuota') - ->with('27 GB'); - - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->uid) - ->willReturn($coreUser); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaNoneProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', ''] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(false); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->never()) - ->method('setQuota'); - - $this->userManager->expects($this->never()) - ->method('get') - ->with($this->uid); - - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaNoneConfigured() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', ''], - ['ldapQuotaDefault', ''] - ]); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->never()) - ->method('setQuota'); - - $this->userManager->expects($this->never()) - ->method('get'); - - $this->access->expects($this->never()) - ->method('readAttribute'); - - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->user->updateQuota(); - } - - public function testUpdateQuotaFromValue() { - $readQuota = '19 GB'; - - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', ''] - ]); - - $this->access->expects($this->never()) - ->method('readAttribute'); - - $user = $this->createMock(IUser::class); - $user->expects($this->once()) - ->method('setQuota') - ->with($readQuota); - - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->uid) - ->willReturn($user); - - $this->user->updateQuota($readQuota); - } - - /** - * Unparseable quota will fallback to use the LDAP default - */ - public function testUpdateWrongQuotaAllProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', '23 GB'] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(['42 GBwos']); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->once()) - ->method('setQuota') - ->with('23 GB'); - - $this->userManager->expects($this->once()) - ->method('get') - ->with($this->uid) - ->willReturn($coreUser); - - $this->user->updateQuota(); - } - - /** - * No user quota and wrong default will set 'default' as quota - */ - public function testUpdateWrongDefaultQuotaProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', '23 GBwowowo'] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(false); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->never()) - ->method('setQuota'); - - $this->userManager->expects($this->never()) - ->method('get'); - - $this->user->updateQuota(); - } - - /** - * Wrong user quota and wrong default will set 'default' as quota - */ - public function testUpdateWrongQuotaAndDefaultAllProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', 'myquota'], - ['ldapQuotaDefault', '23 GBwowowo'] - ]); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('myquota')) - ->willReturn(['23 flush']); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->never()) - ->method('setQuota'); - - $this->userManager->expects($this->never()) - ->method('get'); - - $this->user->updateQuota(); - } - - /** - * No quota attribute set and wrong default will set 'default' as quota - */ - public function testUpdateWrongDefaultQuotaNotProvided() { - $this->connection->expects($this->exactly(2)) - ->method('__get') - ->willReturnMap([ - ['ldapQuotaAttribute', ''], - ['ldapQuotaDefault', '23 GBwowowo'] - ]); - - $this->access->expects($this->never()) - ->method('readAttribute'); - - $coreUser = $this->createMock(IUser::class); - $coreUser->expects($this->never()) - ->method('setQuota'); - - $this->userManager->expects($this->never()) - ->method('get'); - - $this->user->updateQuota(); - } - - //the testUpdateAvatar series also implicitely tests getAvatarImage - public function XtestUpdateAvatarJpegPhotoProvided() { - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('jpegphoto')) - ->willReturn(['this is a photo']); - - $this->image->expects($this->once()) - ->method('loadFromBase64') - ->willReturn('imageResource'); - $this->image->expects($this->once()) - ->method('valid') - ->willReturn(true); - $this->image->expects($this->once()) - ->method('width') - ->willReturn(128); - $this->image->expects($this->once()) - ->method('height') - ->willReturn(128); - $this->image->expects($this->once()) - ->method('centerCrop') - ->willReturn(true); - $this->image->expects($this->once()) - ->method('data') - ->willReturn('this is a photo'); - - $this->config->expects($this->once()) - ->method('getUserValue') - ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') - ->willReturn(''); - $this->config->expects($this->once()) - ->method('setUserValue') - ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo')); - - $this->filesystemhelper->expects($this->once()) - ->method('isLoaded') - ->willReturn(true); - - $avatar = $this->createMock(IAvatar::class); - $avatar->expects($this->once()) - ->method('set') - ->with($this->isInstanceOf($this->image)); - - $this->avatarManager->expects($this->once()) - ->method('getAvatar') - ->with($this->equalTo($this->uid)) - ->willReturn($avatar); - - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $this->user->updateAvatar(); - } - - public function testUpdateAvatarKnownJpegPhotoProvided() { - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('jpegphoto')) - ->willReturn(['this is a photo']); - - $this->image->expects($this->once()) - ->method('loadFromBase64') - ->willReturn('imageResource'); - $this->image->expects($this->never()) - ->method('valid'); - $this->image->expects($this->never()) - ->method('width'); - $this->image->expects($this->never()) - ->method('height'); - $this->image->expects($this->never()) - ->method('centerCrop'); - $this->image->expects($this->once()) - ->method('data') - ->willReturn('this is a photo'); - - $this->config->expects($this->once()) - ->method('getUserValue') - ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') - ->willReturn(md5('this is a photo')); - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->filesystemhelper->expects($this->never()) - ->method('isLoaded'); - - $avatar = $this->createMock(IAvatar::class); - $avatar->expects($this->never()) - ->method('set'); - - $this->avatarManager->expects($this->never()) - ->method('getAvatar'); - - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $this->assertTrue($this->user->updateAvatar()); - } - - public function XtestUpdateAvatarThumbnailPhotoProvided() { - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($dn === $this->dn - && $attr === 'jpegphoto') { - return false; - } elseif ($dn === $this->dn - && $attr === 'thumbnailphoto') { - return ['this is a photo']; - } - return null; - }); - - $this->image->expects($this->once()) - ->method('loadFromBase64') - ->willReturn('imageResource'); - $this->image->expects($this->once()) - ->method('valid') - ->willReturn(true); - $this->image->expects($this->once()) - ->method('width') - ->willReturn(128); - $this->image->expects($this->once()) - ->method('height') - ->willReturn(128); - $this->image->expects($this->once()) - ->method('centerCrop') - ->willReturn(true); - $this->image->expects($this->once()) - ->method('data') - ->willReturn('this is a photo'); - - $this->config->expects($this->once()) - ->method('getUserValue') - ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') - ->willReturn(''); - $this->config->expects($this->once()) - ->method('setUserValue') - ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', md5('this is a photo')); - - $this->filesystemhelper->expects($this->once()) - ->method('isLoaded') - ->willReturn(true); - - $avatar = $this->createMock(IAvatar::class); - $avatar->expects($this->once()) - ->method('set') - ->with($this->isInstanceOf($this->image)); - - $this->avatarManager->expects($this->once()) - ->method('getAvatar') - ->with($this->equalTo($this->uid)) - ->willReturn($avatar); - - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $this->user->updateAvatar(); - } - - public function testUpdateAvatarCorruptPhotoProvided() { - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($dn === $this->dn - && $attr === 'jpegphoto') { - return false; - } elseif ($dn === $this->dn - && $attr === 'thumbnailphoto') { - return ['this is a photo']; - } - return null; - }); - - $this->image->expects($this->once()) - ->method('loadFromBase64') - ->willReturn(false); - $this->image->expects($this->never()) - ->method('valid'); - $this->image->expects($this->never()) - ->method('width'); - $this->image->expects($this->never()) - ->method('height'); - $this->image->expects($this->never()) - ->method('centerCrop'); - $this->image->expects($this->never()) - ->method('data'); - - $this->config->expects($this->never()) - ->method('getUserValue'); - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->filesystemhelper->expects($this->never()) - ->method('isLoaded'); - - $avatar = $this->createMock(IAvatar::class); - $avatar->expects($this->never()) - ->method('set'); - - $this->avatarManager->expects($this->never()) - ->method('getAvatar'); - - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $this->user->updateAvatar(); - } - - public function XtestUpdateAvatarUnsupportedThumbnailPhotoProvided() { - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($dn === $this->dn - && $attr === 'jpegphoto') { - return false; - } elseif ($dn === $this->dn - && $attr === 'thumbnailphoto') { - return ['this is a photo']; - } - return null; - }); - - $this->image->expects($this->once()) - ->method('loadFromBase64') - ->willReturn('imageResource'); - $this->image->expects($this->once()) - ->method('valid') - ->willReturn(true); - $this->image->expects($this->once()) - ->method('width') - ->willReturn(128); - $this->image->expects($this->once()) - ->method('height') - ->willReturn(128); - $this->image->expects($this->once()) - ->method('centerCrop') - ->willReturn(true); - $this->image->expects($this->once()) - ->method('data') - ->willReturn('this is a photo'); - - $this->config->expects($this->once()) - ->method('getUserValue') - ->with($this->uid, 'user_ldap', 'lastAvatarChecksum', '') - ->willReturn(''); - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->filesystemhelper->expects($this->once()) - ->method('isLoaded') - ->willReturn(true); - - $avatar = $this->createMock(IAvatar::class); - $avatar->expects($this->once()) - ->method('set') - ->with($this->isInstanceOf($this->image)) - ->willThrowException(new \Exception()); - - $this->avatarManager->expects($this->once()) - ->method('getAvatar') - ->with($this->equalTo($this->uid)) - ->willReturn($avatar); - - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $this->assertFalse($this->user->updateAvatar()); - } - - public function testUpdateAvatarNotProvided() { - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - if ($dn === $this->dn - && $attr === 'jpegPhoto') { - return false; - } elseif ($dn === $this->dn - && $attr === 'thumbnailPhoto') { - return false; - } - return null; - }); - - $this->image->expects($this->never()) - ->method('valid'); - $this->image->expects($this->never()) - ->method('width'); - $this->image->expects($this->never()) - ->method('height'); - $this->image->expects($this->never()) - ->method('centerCrop'); - $this->image->expects($this->never()) - ->method('data'); - - $this->config->expects($this->never()) - ->method('getUserValue'); - $this->config->expects($this->never()) - ->method('setUserValue'); - - $this->filesystemhelper->expects($this->never()) - ->method('isLoaded'); - - $this->avatarManager->expects($this->never()) - ->method('getAvatar'); - - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $this->user->updateAvatar(); - } - - public function extStorageHomeDataProvider() { - return [ - [ 'myFolder', null ], - [ '', null, false ], - [ 'myFolder', 'myFolder' ], - ]; - } - - /** - * @dataProvider extStorageHomeDataProvider - */ - public function testUpdateExtStorageHome(string $expected, string $valueFromLDAP = null, bool $isSet = true) { - if ($valueFromLDAP === null) { - $this->connection->expects($this->once()) - ->method('__get') - ->willReturnMap([ - ['ldapExtStorageHomeAttribute', 'homeDirectory'], - ]); - - $return = []; - if ($isSet) { - $return[] = $expected; - } - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->dn, 'homeDirectory') - ->willReturn($return); - } - - if ($expected !== '') { - $this->config->expects($this->once()) - ->method('setUserValue') - ->with($this->uid, 'user_ldap', 'extStorageHome', $expected); - } else { - $this->config->expects($this->once()) - ->method('deleteUserValue') - ->with($this->uid, 'user_ldap', 'extStorageHome'); - } - - $actual = $this->user->updateExtStorageHome($valueFromLDAP); - $this->assertSame($expected, $actual); - } - - public function testMarkLogin() { - $this->config->expects($this->once()) - ->method('setUserValue') - ->with($this->equalTo($this->uid), - $this->equalTo('user_ldap'), - $this->equalTo(User::USER_PREFKEY_FIRSTLOGIN), - $this->equalTo(1)) - ->willReturn(true); - - $this->user->markLogin(); - } - - public function testGetAvatarImageProvided() { - $this->access->expects($this->once()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), - $this->equalTo('jpegphoto')) - ->willReturn(['this is a photo']); - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $photo = $this->user->getAvatarImage(); - $this->assertSame('this is a photo', $photo); - //make sure readAttribute is not called again but the already fetched - //photo is returned - $this->user->getAvatarImage(); - } - - public function testGetAvatarImageDisabled() { - $this->access->expects($this->never()) - ->method('readAttribute') - ->with($this->equalTo($this->dn), $this->anything()); - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn([]); - - $this->assertFalse($this->user->getAvatarImage()); - } - - public function imageDataProvider() { - return [ - [ false, false ], - [ 'corruptData', false ], - [ 'validData', true ], - ]; - } - - public function testProcessAttributes() { - $requiredMethods = [ - 'updateQuota', - 'updateEmail', - 'composeAndStoreDisplayName', - 'storeLDAPUserName', - 'getHomePath', - 'updateAvatar', - 'updateExtStorageHome', - ]; - - /** @var User|\PHPUnit\Framework\MockObject\MockObject $userMock */ - $userMock = $this->getMockBuilder(User::class) - ->setConstructorArgs([ - $this->uid, - $this->dn, - $this->access, - $this->config, - $this->filesystemhelper, - $this->image, - $this->log, - $this->avatarManager, - $this->userManager, - $this->notificationManager - ]) - ->setMethods($requiredMethods) - ->getMock(); - - $this->connection->setConfiguration([ - 'homeFolderNamingRule' => 'homeDirectory' - ]); - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'homeFolderNamingRule') { - return 'attr:homeDirectory'; - } - return $name; - }); - $this->connection->expects($this->any()) - ->method('resolveRule') - ->with('avatar') - ->willReturn(['jpegphoto', 'thumbnailphoto']); - - $record = [ - strtolower($this->connection->ldapQuotaAttribute) => ['4096'], - strtolower($this->connection->ldapEmailAttribute) => ['alice@wonderland.org'], - strtolower($this->connection->ldapUserDisplayName) => ['Aaaaalice'], - strtolower($this->connection->ldapExtStorageHomeAttribute) => ['homeDirectory'], - 'uid' => [$this->uid], - 'homedirectory' => ['Alice\'s Folder'], - 'memberof' => ['cn=groupOne', 'cn=groupTwo'], - 'jpegphoto' => ['here be an image'] - ]; - - foreach ($requiredMethods as $method) { - $userMock->expects($this->once()) - ->method($method); - } - \OC_Hook::clear();//disconnect irrelevant hooks - $userMock->processAttributes($record); - /** @noinspection PhpUnhandledExceptionInspection */ - \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]); - } - - public function emptyHomeFolderAttributeValueProvider() { - return [ - 'empty' => [''], - 'prefixOnly' => ['attr:'], - ]; - } - - /** - * @dataProvider emptyHomeFolderAttributeValueProvider - */ - public function testGetHomePathNotConfigured($attributeValue) { - $this->connection->expects($this->any()) - ->method('__get') - ->with($this->equalTo('homeFolderNamingRule')) - ->willReturn($attributeValue); - - $this->access->expects($this->never()) - ->method('readAttribute'); - - $this->config->expects($this->never()) - ->method('getAppValue'); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertFalse($this->user->getHomePath()); - } - - public function testGetHomePathConfiguredNotAvailableAllowed() { - $this->connection->expects($this->any()) - ->method('__get') - ->with($this->equalTo('homeFolderNamingRule')) - ->willReturn('attr:foobar'); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->willReturn(false); - - // asks for "enforce_home_folder_naming_rule" - $this->config->expects($this->once()) - ->method('getAppValue') - ->willReturn(false); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertFalse($this->user->getHomePath()); - } - - - public function testGetHomePathConfiguredNotAvailableNotAllowed() { - $this->expectException(\Exception::class); - - $this->connection->expects($this->any()) - ->method('__get') - ->with($this->equalTo('homeFolderNamingRule')) - ->willReturn('attr:foobar'); - - $this->access->expects($this->once()) - ->method('readAttribute') - ->willReturn(false); - - // asks for "enforce_home_folder_naming_rule" - $this->config->expects($this->once()) - ->method('getAppValue') - ->willReturn(true); - - $this->user->getHomePath(); - } - - public function displayNameProvider() { - return [ - ['Roland Deschain', '', 'Roland Deschain', false], - ['Roland Deschain', '', 'Roland Deschain', true], - ['Roland Deschain', null, 'Roland Deschain', false], - ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', false], - ['Roland Deschain', 'gunslinger@darktower.com', 'Roland Deschain (gunslinger@darktower.com)', true], - ]; - } - - /** - * @dataProvider displayNameProvider - */ - public function testComposeAndStoreDisplayName($part1, $part2, $expected, $expectTriggerChange) { - $this->config->expects($this->once()) - ->method('setUserValue'); - $oldName = $expectTriggerChange ? 'xxGunslingerxx' : null; - $this->config->expects($this->once()) - ->method('getUserValue') - ->with($this->user->getUsername(), 'user_ldap', 'displayName', null) - ->willReturn($oldName); - - $ncUserObj = $this->createMock(\OC\User\User::class); - if ($expectTriggerChange) { - $ncUserObj->expects($this->once()) - ->method('triggerChange') - ->with('displayName', $expected); - } else { - $ncUserObj->expects($this->never()) - ->method('triggerChange'); - } - $this->userManager->expects($this->once()) - ->method('get') - ->willReturn($ncUserObj); - - $displayName = $this->user->composeAndStoreDisplayName($part1, $part2); - $this->assertSame($expected, $displayName); - } - - public function testComposeAndStoreDisplayNameNoOverwrite() { - $displayName = 'Randall Flagg'; - $this->config->expects($this->never()) - ->method('setUserValue'); - $this->config->expects($this->once()) - ->method('getUserValue') - ->willReturn($displayName); - - $this->userManager->expects($this->never()) - ->method('get'); // Implicit: no triggerChange can be called - - $composedDisplayName = $this->user->composeAndStoreDisplayName($displayName); - $this->assertSame($composedDisplayName, $displayName); - } - - public function testHandlePasswordExpiryWarningDefaultPolicy() { - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapDefaultPPolicyDN') { - return 'cn=default,ou=policies,dc=foo,dc=bar'; - } - if ($name === 'turnOnPasswordChange') { - return '1'; - } - return $name; - }); - - $this->access->expects($this->any()) - ->method('search') - ->willReturnCallback(function ($filter, $base) { - if ($base === $this->dn) { - return [ - [ - 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'], - 'pwdgraceusetime' => [], - ], - ]; - } - if ($base === 'cn=default,ou=policies,dc=foo,dc=bar') { - return [ - [ - 'pwdmaxage' => ['2592000'], - 'pwdexpirewarning' => ['2591999'], - ], - ]; - } - return []; - }); - - $notification = $this->getMockBuilder(INotification::class) - ->disableOriginalConstructor() - ->getMock(); - $notification->expects($this->any()) - ->method('setApp') - ->willReturn($notification); - $notification->expects($this->any()) - ->method('setUser') - ->willReturn($notification); - $notification->expects($this->any()) - ->method('setObject') - ->willReturn($notification); - $notification->expects($this->any()) - ->method('setDateTime') - ->willReturn($notification); - - $this->notificationManager->expects($this->exactly(2)) - ->method('createNotification') - ->willReturn($notification); - $this->notificationManager->expects($this->exactly(1)) - ->method('notify'); - - \OC_Hook::clear();//disconnect irrelevant hooks - \OCP\Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry'); - /** @noinspection PhpUnhandledExceptionInspection */ - \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]); - } - - public function testHandlePasswordExpiryWarningCustomPolicy() { - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapDefaultPPolicyDN') { - return 'cn=default,ou=policies,dc=foo,dc=bar'; - } - if ($name === 'turnOnPasswordChange') { - return '1'; - } - return $name; - }); - - $this->access->expects($this->any()) - ->method('search') - ->willReturnCallback(function ($filter, $base) { - if ($base === $this->dn) { - return [ - [ - 'pwdpolicysubentry' => ['cn=custom,ou=policies,dc=foo,dc=bar'], - 'pwdchangedtime' => [(new \DateTime())->sub(new \DateInterval('P28D'))->format('Ymdhis').'Z'], - 'pwdgraceusetime' => [], - ] - ]; - } - if ($base === 'cn=custom,ou=policies,dc=foo,dc=bar') { - return [ - [ - 'pwdmaxage' => ['2592000'], - 'pwdexpirewarning' => ['2591999'], - ] - ]; - } - return []; - }); - - $notification = $this->getMockBuilder(INotification::class) - ->disableOriginalConstructor() - ->getMock(); - $notification->expects($this->any()) - ->method('setApp') - ->willReturn($notification); - $notification->expects($this->any()) - ->method('setUser') - ->willReturn($notification); - $notification->expects($this->any()) - ->method('setObject') - ->willReturn($notification); - $notification->expects($this->any()) - ->method('setDateTime') - ->willReturn($notification); - - $this->notificationManager->expects($this->exactly(2)) - ->method('createNotification') - ->willReturn($notification); - $this->notificationManager->expects($this->exactly(1)) - ->method('notify'); - - \OC_Hook::clear();//disconnect irrelevant hooks - \OCP\Util::connectHook('OC_User', 'post_login', $this->user, 'handlePasswordExpiry'); - /** @noinspection PhpUnhandledExceptionInspection */ - \OC_Hook::emit('OC_User', 'post_login', ['uid' => $this->uid]); - } -} diff --git a/apps/user_ldap/tests/UserLDAPPluginTest.php b/apps/user_ldap/tests/UserLDAPPluginTest.php deleted file mode 100644 index e1b3cd9215969..0000000000000 --- a/apps/user_ldap/tests/UserLDAPPluginTest.php +++ /dev/null @@ -1,312 +0,0 @@ - - * @author Roeland Jago Douma - * @author Vinicius Cubas Brand - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OC\User\Backend; -use OCA\User_LDAP\UserPluginManager; - -class UserLDAPPluginTest extends \Test\TestCase { - - /** - * @return UserPluginManager - */ - private function getUserPluginManager() { - return new UserPluginManager(); - } - - public function testImplementsActions() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::CREATE_USER); - - $plugin2 = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions']) - ->getMock(); - - $plugin2->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::PROVIDE_AVATAR); - - $pluginManager->register($plugin); - $pluginManager->register($plugin2); - - $this->assertEquals($pluginManager->getImplementedActions(), Backend::CREATE_USER | Backend::PROVIDE_AVATAR); - $this->assertTrue($pluginManager->implementsActions(Backend::CREATE_USER)); - $this->assertTrue($pluginManager->implementsActions(Backend::PROVIDE_AVATAR)); - } - - public function testCreateUser() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'createUser']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::CREATE_USER); - - $plugin->expects($this->once()) - ->method('createUser') - ->with( - $this->equalTo('user'), - $this->equalTo('password') - ); - - $pluginManager->register($plugin); - $pluginManager->createUser('user', 'password'); - } - - - public function testCreateUserNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements createUser in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->createUser('foo','bar'); - } - - public function testSetPassword() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'setPassword']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::SET_PASSWORD); - - $plugin->expects($this->once()) - ->method('setPassword') - ->with( - $this->equalTo('user'), - $this->equalTo('password') - ); - - $pluginManager->register($plugin); - $pluginManager->setPassword('user', 'password'); - } - - - public function testSetPasswordNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements setPassword in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->setPassword('foo','bar'); - } - - public function testGetHome() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'getHome']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::GET_HOME); - - $plugin->expects($this->once()) - ->method('getHome') - ->with( - $this->equalTo('uid') - ); - - $pluginManager->register($plugin); - $pluginManager->getHome('uid'); - } - - - public function testGetHomeNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements getHome in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->getHome('foo'); - } - - public function testGetDisplayName() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'getDisplayName']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::GET_DISPLAYNAME); - - $plugin->expects($this->once()) - ->method('getDisplayName') - ->with( - $this->equalTo('uid') - ); - - $pluginManager->register($plugin); - $pluginManager->getDisplayName('uid'); - } - - - public function testGetDisplayNameNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements getDisplayName in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->getDisplayName('foo'); - } - - public function testSetDisplayName() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'setDisplayName']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::SET_DISPLAYNAME); - - $plugin->expects($this->once()) - ->method('setDisplayName') - ->with( - $this->equalTo('user'), - $this->equalTo('password') - ); - - $pluginManager->register($plugin); - $pluginManager->setDisplayName('user', 'password'); - } - - - public function testSetDisplayNameNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements setDisplayName in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->setDisplayName('foo', 'bar'); - } - - public function testCanChangeAvatar() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'canChangeAvatar']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::PROVIDE_AVATAR); - - $plugin->expects($this->once()) - ->method('canChangeAvatar') - ->with( - $this->equalTo('uid') - ); - - $pluginManager->register($plugin); - $pluginManager->canChangeAvatar('uid'); - } - - - public function testCanChangeAvatarNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements canChangeAvatar in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->canChangeAvatar('foo'); - } - - public function testCountUsers() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'countUsers']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(Backend::COUNT_USERS); - - $plugin->expects($this->once()) - ->method('countUsers'); - - $pluginManager->register($plugin); - $pluginManager->countUsers(); - } - - - public function testCountUsersNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements countUsers in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->countUsers(); - } - - public function testDeleteUser() { - $pluginManager = $this->getUserPluginManager(); - - $plugin = $this->getMockBuilder('OCA\User_LDAP\Tests\LDAPUserPluginDummy') - ->setMethods(['respondToActions', 'canDeleteUser','deleteUser']) - ->getMock(); - - $plugin->expects($this->any()) - ->method('respondToActions') - ->willReturn(0); - - $plugin->expects($this->any()) - ->method('canDeleteUser') - ->willReturn(true); - - $plugin->expects($this->once()) - ->method('deleteUser') - ->with( - $this->equalTo('uid') - ); - - $this->assertFalse($pluginManager->canDeleteUser()); - $pluginManager->register($plugin); - $this->assertTrue($pluginManager->canDeleteUser()); - $pluginManager->deleteUser('uid'); - } - - - public function testDeleteUserNotRegistered() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('No plugin implements deleteUser in this LDAP Backend.'); - - $pluginManager = $this->getUserPluginManager(); - $pluginManager->deleteUser('foo'); - } -} diff --git a/apps/user_ldap/tests/User_LDAPTest.php b/apps/user_ldap/tests/User_LDAPTest.php deleted file mode 100644 index 1c10e9955b3fe..0000000000000 --- a/apps/user_ldap/tests/User_LDAPTest.php +++ /dev/null @@ -1,1453 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Jörn Friedrich Dreyer - * @author Lukas Reschke - * @author Morris Jobke - * @author Robin McCorkell - * @author Roeland Jago Douma - * @author Roger Szabo - * @author Thomas Müller - * @author Vinicius Cubas Brand - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests; - -use OC\HintException; -use OC\User\Backend; -use OC\User\Session; -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Connection; -use OCA\User_LDAP\Mapping\AbstractMapping; -use OCA\User_LDAP\Mapping\UserMapping; -use OCA\User_LDAP\User\Manager; -use OCA\User_LDAP\User\OfflineUser; -use OCA\User_LDAP\User\User; -use OCA\User_LDAP\User_LDAP; -use OCA\User_LDAP\User_LDAP as UserLDAP; -use OCA\User_LDAP\UserPluginManager; -use OCP\IConfig; -use OCP\IUser; -use OCP\Notification\IManager as INotificationManager; -use Test\TestCase; - -/** - * Class Test_User_Ldap_Direct - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class User_LDAPTest extends TestCase { - /** @var User_LDAP */ - protected $backend; - /** @var Access|\PHPUnit\Framework\MockObject\MockObject */ - protected $access; - /** @var OfflineUser|\PHPUnit\Framework\MockObject\MockObject */ - protected $offlineUser; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - protected $config; - /** @var INotificationManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $notificationManager; - /** @var Session|\PHPUnit\Framework\MockObject\MockObject */ - protected $session; - /** @var UserPluginManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $pluginManager; - /** @var Connection|\PHPUnit\Framework\MockObject\MockObject */ - protected $connection; - /** @var Manager|\PHPUnit\Framework\MockObject\MockObject */ - protected $userManager; - - protected function setUp(): void { - parent::setUp(); - - \OC_User::clearBackends(); - \OC::$server->getGroupManager()->clearBackends(); - - $this->connection = $this->createMock(Connection::class); - $this->userManager = $this->createMock(Manager::class); - - $this->access = $this->createMock(Access::class); - $this->access->connection = $this->connection; - $this->access->userManager = $this->userManager; - - $this->config = $this->createMock(IConfig::class); - $this->notificationManager = $this->createMock(INotificationManager::class); - // Cannot use IUserSession because of private listen() methods - $this->session = $this->createMock(Session::class); - $this->pluginManager = $this->createMock(UserPluginManager::class); - - $this->backend = new User_LDAP( - $this->access, - $this->config, - $this->notificationManager, - $this->session, - $this->pluginManager - ); - } - - private function prepareMockForUserExists() { - $this->access->expects($this->any()) - ->method('username2dn') - ->willReturnCallback(function ($uid) { - switch ($uid) { - case 'gunslinger': - return 'dnOfRoland,dc=test'; - break; - case 'formerUser': - return 'dnOfFormerUser,dc=test'; - break; - case 'newyorker': - return 'dnOfNewYorker,dc=test'; - break; - case 'ladyofshadows': - return 'dnOfLadyOfShadows,dc=test'; - break; - default: - return false; - } - }); - - $this->access->method('fetchUsersByLoginName') - ->willReturn([]); - } - - /** - * Prepares the Access mock for checkPassword tests - * @param bool $noDisplayName - * @return void - */ - private function prepareAccessForCheckPassword($noDisplayName = false) { - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapLoginFilter') { - return '%uid'; - } - return null; - }); - - $this->access->expects($this->any()) - ->method('fetchListOfUsers') - ->willReturnCallback(function ($filter) { - if ($filter === 'roland') { - return [['dn' => ['dnOfRoland,dc=test']]]; - } - return []; - }); - $this->access->expects($this->any()) - ->method('fetchUsersByLoginName') - ->willReturnCallback(function ($uid) { - if ($uid === 'roland') { - return [['dn' => ['dnOfRoland,dc=test']]]; - } - return []; - }); - - $retVal = 'gunslinger'; - if ($noDisplayName === true) { - $retVal = false; - } - $this->access->expects($this->any()) - ->method('dn2username') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->willReturn($retVal); - $this->access->expects($this->any()) - ->method('stringResemblesDN') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->willReturn(true); - $this->access->expects($this->any()) - ->method('areCredentialsValid') - ->willReturnCallback(function ($dn, $pwd) { - if ($pwd === 'dt19') { - return true; - } - return false; - }); - - $this->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - } - - public function testCheckPasswordUidReturn() { - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getUsername') - ->willReturn('gunslinger'); - - $this->prepareAccessForCheckPassword(); - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($user); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - \OC_User::useBackend($backend); - - $result = $backend->checkPassword('roland', 'dt19'); - $this->assertEquals('gunslinger', $result); - } - - public function testCheckPasswordWrongPassword() { - $this->prepareAccessForCheckPassword(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $backend->checkPassword('roland', 'wrong'); - $this->assertFalse($result); - } - - public function testCheckPasswordWrongUser() { - $this->prepareAccessForCheckPassword(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $backend->checkPassword('mallory', 'evil'); - $this->assertFalse($result); - } - - public function testCheckPasswordNoDisplayName() { - $this->prepareAccessForCheckPassword(true); - - $this->prepareAccessForCheckPassword(); - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn(null); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $backend->checkPassword('roland', 'dt19'); - $this->assertFalse($result); - } - - public function testCheckPasswordPublicAPI() { - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getUsername') - ->willReturn('gunslinger'); - - $this->prepareAccessForCheckPassword(); - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($user); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $user = \OC::$server->getUserManager()->checkPassword('roland', 'dt19'); - $result = false; - if ($user !== false) { - $result = $user->getUID(); - } - $this->assertEquals('gunslinger', $result); - } - - public function testCheckPasswordPublicAPIWrongPassword() { - $this->prepareAccessForCheckPassword(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $user = \OC::$server->getUserManager()->checkPassword('roland', 'wrong'); - $result = false; - if ($user !== false) { - $result = $user->getUID(); - } - $this->assertFalse($result); - } - - public function testCheckPasswordPublicAPIWrongUser() { - $this->prepareAccessForCheckPassword(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $user = \OC::$server->getUserManager()->checkPassword('mallory', 'evil'); - $result = false; - if ($user !== false) { - $result = $user->getUID(); - } - $this->assertFalse($result); - } - - public function testDeleteUserCancel() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $result = $backend->deleteUser('notme'); - $this->assertFalse($result); - } - - public function testDeleteUserSuccess() { - $uid = 'jeremy'; - $home = '/var/vhome/jdings/'; - - $mapping = $this->createMock(UserMapping::class); - $mapping->expects($this->once()) - ->method('unmap') - ->willReturn(true); - $this->access->expects($this->once()) - ->method('getUserMapper') - ->willReturn($mapping); - $this->connection->expects($this->any()) - ->method('getConnectionResource') - ->willReturn('this is an ldap link'); - - $this->config->expects($this->any()) - ->method('getUserValue') - ->with($uid, 'user_ldap', 'isDeleted') - ->willReturn('1'); - - $offlineUser = $this->createMock(OfflineUser::class); - $offlineUser->expects($this->once()) - ->method('getHomePath') - ->willReturn($home); - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($offlineUser); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->deleteUser($uid); - $this->assertTrue($result); - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertSame($backend->getHome($uid), $home); - } - - public function testDeleteUserWithPlugin() { - $this->pluginManager->expects($this->once()) - ->method('canDeleteUser') - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('deleteUser') - ->with('uid') - ->willReturn(true); - - $this->config->expects($this->once()) - ->method('getUserValue') - ->with('uid', 'user_ldap', 'isDeleted', 0) - ->willReturn(1); - - $mapper = $this->createMock(UserMapping::class); - $mapper->expects($this->once()) - ->method('unmap') - ->with('uid'); - - $this->access->expects($this->atLeastOnce()) - ->method('getUserMapper') - ->willReturn($mapper); - - $this->userManager->expects($this->once()) - ->method('invalidate') - ->with('uid'); - - $this->assertEquals(true, $this->backend->deleteUser('uid')); - } - - /** - * Prepares the Access mock for getUsers tests - */ - private function prepareAccessForGetUsers() { - $this->access->expects($this->once()) - ->method('escapeFilterPart') - ->willReturnCallback(function ($search) { - return $search; - }); - $this->access->expects($this->any()) - ->method('getFilterPartForUserSearch') - ->willReturnCallback(function ($search) { - return $search; - }); - $this->access->expects($this->any()) - ->method('combineFilterWithAnd') - ->willReturnCallback(function ($param) { - return $param[2]; - }); - $this->access->expects($this->any()) - ->method('fetchListOfUsers') - ->willReturnCallback(function ($search, $a, $l, $o) { - $users = ['gunslinger', 'newyorker', 'ladyofshadows']; - if (empty($search)) { - $result = $users; - } else { - $result = []; - foreach ($users as $user) { - if (stripos($user, $search) !== false) { - $result[] = $user; - } - } - } - if (!is_null($l) || !is_null($o)) { - $result = array_slice($result, $o, $l); - } - return $result; - }); - $this->access->expects($this->any()) - ->method('nextcloudUserNames') - ->willReturnArgument(0); - $this->access->method('fetchUsersByLoginName') - ->willReturn([]); - - $this->access->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - } - - public function testGetUsersNoParam() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->getUsers(); - $this->assertEquals(3, count($result)); - } - - public function testGetUsersLimitOffset() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->getUsers('', 1, 2); - $this->assertEquals(1, count($result)); - } - - public function testGetUsersLimitOffset2() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->getUsers('', 2, 1); - $this->assertEquals(2, count($result)); - } - - public function testGetUsersSearchWithResult() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->getUsers('yo'); - $this->assertEquals(2, count($result)); - } - - public function testGetUsersSearchEmptyResult() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->getUsers('nix'); - $this->assertEquals(0, count($result)); - } - - private function getUsers($search = '', $limit = null, $offset = null) { - $users = \OC::$server->getUserManager()->search($search, $limit, $offset); - $uids = array_map(function (IUser $user) { - return $user->getUID(); - }, $users); - return $uids; - } - - public function testGetUsersViaAPINoParam() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $this->getUsers(); - $this->assertEquals(3, count($result)); - } - - public function testGetUsersViaAPILimitOffset() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $this->getUsers('', 1, 2); - $this->assertEquals(1, count($result)); - } - - public function testGetUsersViaAPILimitOffset2() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $this->getUsers('', 2, 1); - $this->assertEquals(2, count($result)); - } - - public function testGetUsersViaAPISearchWithResult() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $this->getUsers('yo'); - $this->assertEquals(2, count($result)); - } - - public function testGetUsersViaAPISearchEmptyResult() { - $this->prepareAccessForGetUsers(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $result = $this->getUsers('nix'); - $this->assertEquals(0, count($result)); - } - - public function testUserExists() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $user = $this->createMock(User::class); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($this->createMock(UserMapping::class)); - - //test for existing user - /** @noinspection PhpUnhandledExceptionInspection */ - $result = $backend->userExists('gunslinger'); - $this->assertTrue($result); - } - - public function testUserExistsForDeleted() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $mapper = $this->createMock(UserMapping::class); - $mapper->expects($this->any()) - ->method('getUUIDByDN') - ->with('dnOfFormerUser,dc=test') - ->willReturn('45673458748'); - - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($mapper); - - $user = $this->createMock(User::class); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - - //test for deleted user – always returns true as long as we have the user in DB - $this->assertTrue($backend->userExists('formerUser')); - } - - public function testUserExistsForNeverExisting() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn) { - if ($dn === 'dnOfRoland,dc=test') { - return []; - } - return false; - }); - - //test for never-existing user - /** @noinspection PhpUnhandledExceptionInspection */ - $result = $backend->userExists('mallory'); - $this->assertFalse($result); - } - - public function testUserExistsPublicAPI() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - \OC_User::useBackend($backend); - - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getDN') - ->willReturn('dnOfRoland,dc=test'); - - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn) { - if ($dn === 'dnOfRoland,dc=test') { - return []; - } - return false; - }); - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($this->createMock(UserMapping::class)); - - //test for existing user - $result = \OC::$server->getUserManager()->userExists('gunslinger'); - $this->assertTrue($result); - } - - public function testDeleteUserExisting() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - //we do not support deleting existing users at all - $result = $backend->deleteUser('gunslinger'); - $this->assertFalse($result); - } - - public function testGetHomeAbsolutePath() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'homeFolderNamingRule') { - return 'attr:testAttribute'; - } - return null; - }); - - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - switch ($dn) { - case 'dnOfRoland,dc=test': - if ($attr === 'testAttribute') { - return ['/tmp/rolandshome/']; - } - return []; - break; - default: - return false; - } - }); - - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getUsername') - ->willReturn('gunslinger'); - $user->expects($this->any()) - ->method('getDN') - ->willReturn('dnOfRoland,dc=test'); - $user->expects($this->any()) - ->method('getHomePath') - ->willReturn('/tmp/rolandshome/'); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - - //absolute path - /** @noinspection PhpUnhandledExceptionInspection */ - $result = $backend->getHome('gunslinger'); - $this->assertEquals('/tmp/rolandshome/', $result); - } - - public function testGetHomeRelative() { - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $dataDir = \OC::$server->getConfig()->getSystemValue( - 'datadirectory', \OC::$SERVERROOT.'/data'); - - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'homeFolderNamingRule') { - return 'attr:testAttribute'; - } - return null; - }); - - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - switch ($dn) { - case 'dnOfLadyOfShadows,dc=test': - if ($attr === 'testAttribute') { - return ['susannah/']; - } - return []; - break; - default: - return false; - } - }); - - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getUsername') - ->willReturn('ladyofshadows'); - $user->expects($this->any()) - ->method('getDN') - ->willReturn('dnOfLadyOfShadows,dc=test'); - $user->expects($this->any()) - ->method('getHomePath') - ->willReturn($dataDir.'/susannah/'); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - - /** @noinspection PhpUnhandledExceptionInspection */ - $result = $backend->getHome('ladyofshadows'); - $this->assertEquals($dataDir.'/susannah/', $result); - } - - - public function testGetHomeNoPath() { - $this->expectException(\Exception::class); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'homeFolderNamingRule') { - return 'attr:testAttribute'; - } - return null; - }); - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - switch ($dn) { - default: - return false; - } - }); - $this->access->connection->expects($this->any()) - ->method('getFromCache') - ->willReturnCallback(function ($key) { - if ($key === 'userExistsnewyorker') { - return true; - } - return null; - }); - - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getUsername') - ->willReturn('newyorker'); - $user->expects($this->any()) - ->method('getHomePath') - ->willThrowException(new \Exception()); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - - //no path at all – triggers OC default behaviour - $result = $backend->getHome('newyorker'); - $this->assertFalse($result); - } - - public function testGetHomeDeletedUser() { - $uid = 'newyorker'; - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'homeFolderNamingRule') { - return 'attr:testAttribute'; - } - return null; - }); - - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturn([]); - - $userMapper = $this->createMock(UserMapping::class); - - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($userMapper); - - $this->config->expects($this->any()) - ->method('getUserValue') - ->willReturn(true); - - $offlineUser = $this->createMock(OfflineUser::class); - $offlineUser->expects($this->atLeastOnce()) - ->method('getHomePath') - ->willReturn(''); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($offlineUser); - - $result = $backend->getHome($uid); - $this->assertFalse($result); - } - - public function testGetHomeWithPlugin() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::GET_HOME) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('getHome') - ->with('uid') - ->willReturn('result'); - - $this->connection->expects($this->any()) - ->method('getFromCache') - ->willReturnCallback(function ($uid) { - return true; - }); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertEquals($this->backend->getHome('uid'),'result'); - } - - private function prepareAccessForGetDisplayName() { - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapUserDisplayName') { - return 'displayname'; - } - return null; - }); - - $this->access->expects($this->any()) - ->method('readAttribute') - ->willReturnCallback(function ($dn, $attr) { - switch ($dn) { - case 'dnOfRoland,dc=test': - if ($attr === 'displayname') { - return ['Roland Deschain']; - } - return []; - break; - - default: - return false; - } - }); - $this->access->method('fetchUsersByLoginName') - ->willReturn([]); - } - - public function testGetDisplayName() { - $this->prepareAccessForGetDisplayName(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $this->connection->expects($this->any()) - ->method('getConnectionResource') - ->willReturnCallback(function () { - return true; - }); - - $user1 = $this->createMock(User::class); - $user1->expects($this->once()) - ->method('composeAndStoreDisplayName') - ->willReturn('Roland Deschain'); - $user1->expects($this->any()) - ->method('getDN') - ->willReturn('dnOfRoland,dc=test'); - - $user2 = $this->createMock(User::class); - $user2->expects($this->never()) - ->method('composeAndStoreDisplayName'); - $user2->expects($this->any()) - ->method('getDN') - ->willReturn('another DN'); - - $mapper = $this->createMock(UserMapping::class); - $mapper->expects($this->any()) - ->method('getUUIDByDN') - ->willReturnCallback(function ($dn) { - return $dn; - }); - - $this->userManager->expects($this->any()) - ->method('get') - ->willReturnCallback(function ($uid) use ($user1, $user2) { - if ($uid === 'gunslinger') { - return $user1; - } elseif ($uid === 'newyorker') { - return $user2; - } - return null; - }); - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($mapper); - $this->access->expects($this->any()) - ->method('getUserDnByUuid') - ->willReturnCallback(function ($uuid) { - return $uuid . '1'; - }); - - //with displayName - $result = $backend->getDisplayName('gunslinger'); - $this->assertEquals('Roland Deschain', $result); - - //empty displayname retrieved - $result = $backend->getDisplayName('newyorker'); - $this->assertEquals(null, $result); - } - - public function testGetDisplayNamePublicAPI() { - $this->access->expects($this->any()) - ->method('username2dn') - ->willReturnCallback(function ($uid) { - switch ($uid) { - case 'gunslinger': - return 'dnOfRoland,dc=test'; - break; - case 'formerUser': - return 'dnOfFormerUser,dc=test'; - break; - case 'newyorker': - return 'dnOfNewYorker,dc=test'; - break; - case 'ladyofshadows': - return 'dnOfLadyOfShadows,dc=test'; - break; - default: - return false; - } - }); - $this->prepareAccessForGetDisplayName(); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->prepareMockForUserExists(); - - $this->connection->expects($this->any()) - ->method('getConnectionResource') - ->willReturnCallback(function () { - return true; - }); - - \OC_User::useBackend($backend); - - $user1 = $this->createMock(User::class); - $user1->expects($this->once()) - ->method('composeAndStoreDisplayName') - ->willReturn('Roland Deschain'); - $user1->expects($this->any()) - ->method('getDN') - ->willReturn('dnOfRoland,dc=test'); - - $user2 = $this->createMock(User::class); - $user2->expects($this->never()) - ->method('composeAndStoreDisplayName'); - $user2->expects($this->any()) - ->method('getDN') - ->willReturn('another DN'); - - $mapper = $this->createMock(UserMapping::class); - $mapper->expects($this->any()) - ->method('getUUIDByDN') - ->willReturnCallback(function ($dn) { - return $dn; - }); - - $this->userManager->expects($this->any()) - ->method('get') - ->willReturnCallback(function ($uid) use ($user1, $user2) { - if ($uid === 'gunslinger') { - return $user1; - } elseif ($uid === 'newyorker') { - return $user2; - } - return null; - }); - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($mapper); - $this->access->expects($this->any()) - ->method('getUserDnByUuid') - ->willReturnCallback(function ($uuid) { - return $uuid . '1'; - }); - - //with displayName - $result = \OC::$server->getUserManager()->get('gunslinger')->getDisplayName(); - $this->assertEquals('Roland Deschain', $result); - - //empty displayname retrieved - $result = \OC::$server->getUserManager()->get('newyorker') === null ? 'newyorker' : \OC::$server->getUserManager()->get('newyorker')->getDisplayName(); - $this->assertEquals('newyorker', $result); - } - - public function testGetDisplayNameWithPlugin() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::GET_DISPLAYNAME) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('getDisplayName') - ->with('uid') - ->willReturn('result'); - - $this->assertEquals($this->backend->getDisplayName('uid'),'result'); - } - - //no test for getDisplayNames, because it just invokes getUsers and - //getDisplayName - - public function testCountUsers() { - $this->access->expects($this->once()) - ->method('countUsers') - ->willReturn(5); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->countUsers(); - $this->assertEquals(5, $result); - } - - public function testCountUsersFailing() { - $this->access->expects($this->once()) - ->method('countUsers') - ->willReturn(false); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - - $result = $backend->countUsers(); - $this->assertFalse($result); - } - - public function testCountUsersWithPlugin() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::COUNT_USERS) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('countUsers') - ->willReturn(42); - - $this->assertEquals($this->backend->countUsers(),42); - } - - public function testLoginName2UserNameSuccess() { - $loginName = 'Alice'; - $username = 'alice'; - $dn = 'uid=alice,dc=what,dc=ever'; - - $this->access->expects($this->once()) - ->method('fetchUsersByLoginName') - ->with($this->equalTo($loginName)) - ->willReturn([['dn' => [$dn]]]); - $this->access->expects($this->any()) - ->method('stringResemblesDN') - ->with($this->equalTo($dn)) - ->willReturn(true); - $this->access->expects($this->any()) - ->method('dn2username') - ->with($this->equalTo($dn)) - ->willReturn($username); - - $this->connection->expects($this->exactly(2)) - ->method('getFromCache') - ->with($this->equalTo('loginName2UserName-'.$loginName)) - ->willReturnOnConsecutiveCalls(null, $username); - $this->connection->expects($this->once()) - ->method('writeToCache') - ->with($this->equalTo('loginName2UserName-'.$loginName), $this->equalTo($username)); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $user = $this->createMock(User::class); - $user->expects($this->any()) - ->method('getUsername') - ->willReturn('alice'); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->with($dn) - ->willReturn($user); - $this->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - - $name = $backend->loginName2UserName($loginName); - $this->assertSame($username, $name); - - // and once again to verify that caching works - $backend->loginName2UserName($loginName); - } - - public function testLoginName2UserNameNoUsersOnLDAP() { - $loginName = 'Loki'; - - $this->access->expects($this->once()) - ->method('fetchUsersByLoginName') - ->with($this->equalTo($loginName)) - ->willReturn([]); - $this->access->expects($this->never()) - ->method('stringResemblesDN'); - $this->access->expects($this->never()) - ->method('dn2username'); - - $this->connection->expects($this->exactly(2)) - ->method('getFromCache') - ->with($this->equalTo('loginName2UserName-'.$loginName)) - ->willReturnOnConsecutiveCalls(null, false); - $this->connection->expects($this->once()) - ->method('writeToCache') - ->with($this->equalTo('loginName2UserName-'.$loginName), false); - - $this->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $name = $backend->loginName2UserName($loginName); - $this->assertSame(false, $name); - - // and once again to verify that caching works - $backend->loginName2UserName($loginName); - } - - public function testLoginName2UserNameOfflineUser() { - $loginName = 'Alice'; - $dn = 'uid=alice,dc=what,dc=ever'; - - $offlineUser = $this->getMockBuilder(OfflineUser::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->access->expects($this->once()) - ->method('fetchUsersByLoginName') - ->with($this->equalTo($loginName)) - ->willReturn([['dn' => [$dn]]]); - - $this->connection->expects($this->exactly(2)) - ->method('getFromCache') - ->with($this->equalTo('loginName2UserName-'.$loginName)) - ->willReturnOnConsecutiveCalls(null, false); - $this->connection->expects($this->once()) - ->method('writeToCache') - ->with($this->equalTo('loginName2UserName-'.$loginName), $this->equalTo(false)); - - $this->userManager->expects($this->any()) - ->method('get') - ->with($dn) - ->willReturn($offlineUser); - $this->userManager->expects($this->any()) - ->method('getAttributes') - ->willReturn(['dn', 'uid', 'mail', 'displayname']); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $name = $backend->loginName2UserName($loginName); - $this->assertSame(false, $name); - - // and once again to verify that caching works - $backend->loginName2UserName($loginName); - } - - /** - * Prepares the Access mock for setPassword tests - * - * @param bool $enablePasswordChange - */ - private function prepareAccessForSetPassword($enablePasswordChange = true) { - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) use (&$enablePasswordChange) { - if ($name === 'ldapLoginFilter') { - return '%uid'; - } - if ($name === 'turnOnPasswordChange') { - return $enablePasswordChange?1:0; - } - return null; - }); - $this->connection->expects($this->any()) - ->method('getFromCache') - ->willReturnCallback(function ($uid) { - if ($uid === 'userExists'.'roland') { - return true; - } - return null; - }); - - $this->access->expects($this->any()) - ->method('fetchListOfUsers') - ->willReturnCallback(function ($filter) { - if ($filter === 'roland') { - return [['dn' => ['dnOfRoland,dc=test']]]; - } - return []; - }); - $this->access->expects($this->any()) - ->method('fetchUsersByLoginName') - ->willReturnCallback(function ($uid) { - if ($uid === 'roland') { - return [['dn' => ['dnOfRoland,dc=test']]]; - } - return []; - }); - $this->access->expects($this->any()) - ->method('dn2username') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->willReturn('roland'); - $this->access->expects($this->any()) - ->method('stringResemblesDN') - ->with($this->equalTo('dnOfRoland,dc=test')) - ->willReturn(true); - $this->access->expects($this->any()) - ->method('setPassword') - ->willReturnCallback(function ($uid, $password) { - if (strlen($password) <= 5) { - throw new HintException('Password fails quality checking policy', '', 19); - } - return true; - }); - } - - - public function testSetPasswordInvalid() { - $this->expectException(\OC\HintException::class); - $this->expectExceptionMessage('Password fails quality checking policy'); - - $this->prepareAccessForSetPassword($this->access); - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($this->createMock(User::class)); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $this->assertTrue(\OC_User::setPassword('roland', 'dt')); - } - - public function testSetPasswordValid() { - $this->prepareAccessForSetPassword($this->access); - - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($this->createMock(User::class)); - - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($this->createMock(User::class)); - - \OC_User::useBackend($backend); - - $this->assertTrue(\OC_User::setPassword('roland', 'dt12234$')); - } - - public function testSetPasswordValidDisabled() { - $this->userManager->expects($this->any()) - ->method('get') - ->willReturn($this->createMock(User::class)); - - $this->prepareAccessForSetPassword(false); - $backend = new UserLDAP($this->access, $this->config, $this->notificationManager, $this->session, $this->pluginManager); - \OC_User::useBackend($backend); - - $this->assertFalse(\OC_User::setPassword('roland', 'dt12234$')); - } - - - public function testSetPasswordWithInvalidUser() { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('LDAP setPassword: Could not get user object for uid NotExistingUser. Maybe the LDAP entry has no set display name attribute?'); - - $this->userManager - ->expects($this->once()) - ->method('get') - ->with('NotExistingUser') - ->willReturn(null); - - $this->backend->setPassword('NotExistingUser', 'Password'); - } - - public function testSetPasswordWithUsernameFalse() { - $user = $this->createMock(User::class); - $user - ->expects($this->once()) - ->method('getUsername') - ->willReturn(false); - $this->userManager - ->expects($this->once()) - ->method('get') - ->with('NotExistingUser') - ->willReturn($user); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertFalse($this->backend->setPassword('NotExistingUser', 'Password')); - } - - public function testSetPasswordWithPlugin() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::SET_PASSWORD) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('setPassword') - ->with('uid','password') - ->willReturn('result'); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertEquals($this->backend->setPassword('uid', 'password'),'result'); - } - - public function avatarDataProvider() { - return [ - [ 'validImageData', false ], - [ 'corruptImageData', true ], - [ false, true] - ]; - } - - /** @dataProvider avatarDataProvider */ - public function testCanChangeAvatar($imageData, $expected) { - $isValidImage = strpos((string)$imageData, 'valid') === 0; - - $user = $this->createMock(User::class); - $user->expects($this->once()) - ->method('getAvatarImage') - ->willReturn($imageData); - $user->expects($this->atMost(1)) - ->method('updateAvatar') - ->willReturn($isValidImage); - - $this->userManager->expects($this->atLeastOnce()) - ->method('get') - ->willReturn($user); - - /** @noinspection PhpUnhandledExceptionInspection */ - $this->assertSame($expected, $this->backend->canChangeAvatar('uid')); - } - - public function testCanChangeAvatarWithPlugin() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::PROVIDE_AVATAR) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('canChangeAvatar') - ->with('uid') - ->willReturn('result'); - - $this->assertEquals($this->backend->canChangeAvatar('uid'),'result'); - } - - public function testSetDisplayNameWithPlugin() { - $newDisplayName = 'J. Baker'; - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::SET_DISPLAYNAME) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('setDisplayName') - ->with('uid', $newDisplayName) - ->willReturn($newDisplayName); - $this->access->expects($this->once()) - ->method('cacheUserDisplayName'); - - $this->assertEquals($newDisplayName, $this->backend->setDisplayName('uid', $newDisplayName)); - } - - - public function testSetDisplayNameErrorWithPlugin() { - $this->expectException(\OC\HintException::class); - - $newDisplayName = 'J. Baker'; - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::SET_DISPLAYNAME) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('setDisplayName') - ->with('uid', $newDisplayName) - ->willThrowException(new HintException('something happned')); - $this->access->expects($this->never()) - ->method('cacheUserDisplayName'); - - $this->backend->setDisplayName('uid', $newDisplayName); - } - - public function testSetDisplayNameFailing() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::SET_DISPLAYNAME) - ->willReturn(false); - $this->access->expects($this->never()) - ->method('cacheUserDisplayName'); - - $this->assertFalse($this->backend->setDisplayName('uid', 'displayName')); - } - - public function testCreateUserWithPlugin() { - $uid = 'alien6372'; - $uuid = '123-2345-36756-123-2345234-4431'; - $pwd = 'passwørd'; - - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::CREATE_USER) - ->willReturn(true); - $this->pluginManager->expects($this->once()) - ->method('createUser') - ->with($uid, $pwd) - ->willReturn('result'); - - $this->access->expects($this->atLeastOnce()) - ->method('getUUID') - ->willReturn($uuid); - $this->access->expects($this->once()) - ->method('mapAndAnnounceIfApplicable') - ->with($this->isInstanceOf(AbstractMapping::class), $this->anything(), $uid, $uuid, true); - $this->access->expects($this->any()) - ->method('getUserMapper') - ->willReturn($this->createMock(AbstractMapping::class)); - - $this->assertEquals($this->backend->createUser($uid, $pwd),true); - } - - public function testCreateUserFailing() { - $this->pluginManager->expects($this->once()) - ->method('implementsActions') - ->with(Backend::CREATE_USER) - ->willReturn(false); - - $this->assertFalse($this->backend->createUser('uid', 'password')); - } - - public function actionProvider() { - return [ - [ 'ldapUserAvatarRule', 'default', Backend::PROVIDE_AVATAR, true] , - [ 'ldapUserAvatarRule', 'data:selfiePhoto', Backend::PROVIDE_AVATAR, true], - [ 'ldapUserAvatarRule', 'none', Backend::PROVIDE_AVATAR, false], - [ 'turnOnPasswordChange', 0, Backend::SET_PASSWORD, false], - [ 'turnOnPasswordChange', 1, Backend::SET_PASSWORD, true], - ]; - } - - /** - * @dataProvider actionProvider - */ - public function testImplementsAction($configurable, $value, $actionCode, $expected) { - $this->pluginManager->expects($this->once()) - ->method('getImplementedActions') - ->willReturn(0); - - $this->connection->expects($this->any()) - ->method('__get') - ->willReturnMap([ - [$configurable, $value], - ]); - - $this->assertSame($expected, $this->backend->implementsActions($actionCode)); - } -} diff --git a/apps/user_ldap/tests/User_ProxyTest.php b/apps/user_ldap/tests/User_ProxyTest.php deleted file mode 100644 index 5753990a73608..0000000000000 --- a/apps/user_ldap/tests/User_ProxyTest.php +++ /dev/null @@ -1,104 +0,0 @@ - - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Lukas Reschke - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Roger Szabo - * @author Vinicius Cubas Brand - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\User_Proxy; -use OCA\User_LDAP\UserPluginManager; -use OCP\IConfig; -use OCP\IUserSession; -use OCP\Notification\IManager as INotificationManager; -use Test\TestCase; - -class User_ProxyTest extends TestCase { - /** @var ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject */ - private $ldapWrapper; - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - /** @var INotificationManager|\PHPUnit\Framework\MockObject\MockObject */ - private $notificationManager; - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - private $userSession; - /** @var User_Proxy|\PHPUnit\Framework\MockObject\MockObject */ - private $proxy; - /** @var UserPluginManager|\PHPUnit\Framework\MockObject\MockObject */ - private $userPluginManager; - - protected function setUp(): void { - parent::setUp(); - - $this->ldapWrapper = $this->createMock(ILDAPWrapper::class); - $this->config = $this->createMock(IConfig::class); - $this->notificationManager = $this->createMock(INotificationManager::class); - $this->userSession = $this->createMock(IUserSession::class); - $this->userPluginManager = $this->createMock(UserPluginManager::class); - $this->proxy = $this->getMockBuilder(User_Proxy::class) - ->setConstructorArgs([ - [], - $this->ldapWrapper, - $this->config, - $this->notificationManager, - $this->userSession, - $this->userPluginManager - ]) - ->setMethods(['handleRequest']) - ->getMock(); - } - - public function testSetPassword() { - $this->proxy - ->expects($this->once()) - ->method('handleRequest') - ->with('MyUid', 'setPassword', ['MyUid', 'MyPassword']) - ->willReturn(true); - - $this->assertTrue($this->proxy->setPassword('MyUid', 'MyPassword')); - } - - public function testSetDisplayName() { - $this->proxy - ->expects($this->once()) - ->method('handleRequest') - ->with('MyUid', 'setDisplayName', ['MyUid', 'MyPassword']) - ->willReturn(true); - - $this->assertTrue($this->proxy->setDisplayName('MyUid', 'MyPassword')); - } - - public function testCreateUser() { - $this->proxy - ->expects($this->once()) - ->method('handleRequest') - ->with('MyUid', 'createUser', ['MyUid', 'MyPassword']) - ->willReturn(true); - - $this->assertTrue($this->proxy->createUser('MyUid', 'MyPassword')); - } -} diff --git a/apps/user_ldap/tests/WizardTest.php b/apps/user_ldap/tests/WizardTest.php deleted file mode 100644 index da3239cb8f8d2..0000000000000 --- a/apps/user_ldap/tests/WizardTest.php +++ /dev/null @@ -1,451 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Thomas Müller - * @author Victor Dubiniuk - * @author Viktor Szépe - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\User_LDAP\Tests; - -use OCA\User_LDAP\Access; -use OCA\User_LDAP\Configuration; -use OCA\User_LDAP\ILDAPWrapper; -use OCA\User_LDAP\Wizard; -use PHPUnit\Framework\MockObject\MockObject; -use Test\TestCase; - -/** - * Class Test_Wizard - * - * @group DB - * - * @package OCA\User_LDAP\Tests - */ -class WizardTest extends TestCase { - protected function setUp(): void { - parent::setUp(); - //we need to make sure the consts are defined, otherwise tests will fail - //on systems without php5_ldap - $ldapConsts = ['LDAP_OPT_PROTOCOL_VERSION', - 'LDAP_OPT_REFERRALS', 'LDAP_OPT_NETWORK_TIMEOUT']; - foreach ($ldapConsts as $const) { - if (!defined($const)) { - define($const, 42); - } - } - } - - private function getWizardAndMocks() { - static $confMethods; - static $connMethods; - static $accMethods; - - if (is_null($confMethods)) { - $confMethods = get_class_methods('\OCA\User_LDAP\Configuration'); - $connMethods = get_class_methods('\OCA\User_LDAP\Connection'); - $accMethods = get_class_methods('\OCA\User_LDAP\Access'); - } - /** @var ILDAPWrapper|\PHPUnit\Framework\MockObject\MockObject $lw */ - $lw = $this->createMock(ILDAPWrapper::class); - - /** @var Configuration|\PHPUnit\Framework\MockObject\MockObject $conf */ - $conf = $this->getMockBuilder(Configuration::class) - ->setMethods($confMethods) - ->setConstructorArgs([$lw, null, null]) - ->getMock(); - - /** @var Access|\PHPUnit\Framework\MockObject\MockObject $access */ - $access = $this->createMock(Access::class); - - return [new Wizard($conf, $lw, $access), $conf, $lw, $access]; - } - - private function prepareLdapWrapperForConnections(MockObject &$ldap) { - $ldap->expects($this->once()) - ->method('connect') - //dummy value, usually invalid - ->willReturn(true); - - $ldap->expects($this->exactly(3)) - ->method('setOption') - ->willReturn(true); - - $ldap->expects($this->once()) - ->method('bind') - ->willReturn(true); - } - - public function testCumulativeSearchOnAttributeLimited() { - list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapBase') { - return ['base']; - } - return null; - }); - - $this->prepareLdapWrapperForConnections($ldap); - - $ldap->expects($this->any()) - ->method('isResource') - ->willReturn(true); - - $ldap->expects($this->exactly(2)) - ->method('search') - //dummy value, usually invalid - ->willReturn(true); - - $ldap->expects($this->exactly(2)) - ->method('countEntries') - //an is_resource check will follow, so we need to return a dummy resource - ->willReturn(23); - - //5 DNs per filter means 2x firstEntry and 8x nextEntry - $ldap->expects($this->exactly(2)) - ->method('firstEntry') - //dummy value, usually invalid - ->willReturn(true); - - $ldap->expects($this->exactly(8)) - ->method('nextEntry') - //dummy value, usually invalid - ->willReturn(true); - - $ldap->expects($this->exactly(10)) - ->method('getAttributes') - //dummy value, usually invalid - ->willReturn(['cn' => ['foo'], 'count' => 1]); - - global $uidnumber; - $uidnumber = 1; - $ldap->expects($this->exactly(10)) - ->method('getDN') - //dummy value, usually invalid - ->willReturnCallback(function ($a, $b) { - global $uidnumber; - return $uidnumber++; - }); - - // The following expectations are the real test - $filters = ['f1', 'f2', '*']; - $wizard->cumulativeSearchOnAttribute($filters, 'cn', 5); - unset($uidnumber); - } - - public function testCumulativeSearchOnAttributeUnlimited() { - list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapBase') { - return ['base']; - } - return null; - }); - - $this->prepareLdapWrapperForConnections($ldap); - - $ldap->expects($this->any()) - ->method('isResource') - ->willReturnCallback(function ($r) { - if ($r === true) { - return true; - } - if ($r % 24 === 0) { - global $uidnumber; - $uidnumber++; - return false; - } - return true; - }); - - $ldap->expects($this->exactly(2)) - ->method('search') - //dummy value, usually invalid - ->willReturn(true); - - $ldap->expects($this->exactly(2)) - ->method('countEntries') - //an is_resource check will follow, so we need to return a dummy resource - ->willReturn(23); - - //5 DNs per filter means 2x firstEntry and 8x nextEntry - $ldap->expects($this->exactly(2)) - ->method('firstEntry') - //dummy value, usually invalid - ->willReturnCallback(function ($r) { - global $uidnumber; - return $uidnumber; - }); - - $ldap->expects($this->exactly(46)) - ->method('nextEntry') - //dummy value, usually invalid - ->willReturnCallback(function ($r) { - global $uidnumber; - return $uidnumber; - }); - - $ldap->expects($this->exactly(46)) - ->method('getAttributes') - //dummy value, usually invalid - ->willReturn(['cn' => ['foo'], 'count' => 1]); - - global $uidnumber; - $uidnumber = 1; - $ldap->expects($this->exactly(46)) - ->method('getDN') - //dummy value, usually invalid - ->willReturnCallback(function ($a, $b) { - global $uidnumber; - return $uidnumber++; - }); - - // The following expectations are the real test - $filters = ['f1', 'f2', '*']; - $wizard->cumulativeSearchOnAttribute($filters, 'cn', 0); - unset($uidnumber); - } - - public function testDetectEmailAttributeAlreadySet() { - list($wizard, $configuration, $ldap, $access) - = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapEmailAttribute') { - return 'myEmailAttribute'; - } else { - //for requirement checks - return 'let me pass'; - } - }); - - $access->expects($this->once()) - ->method('countUsers') - ->willReturn(42); - - $wizard->detectEmailAttribute(); - } - - public function testDetectEmailAttributeOverrideSet() { - list($wizard, $configuration, $ldap, $access) - = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapEmailAttribute') { - return 'myEmailAttribute'; - } else { - //for requirement checks - return 'let me pass'; - } - }); - - $access->expects($this->exactly(3)) - ->method('combineFilterWithAnd') - ->willReturnCallback(function ($filterParts) { - return str_replace('=*', '', array_pop($filterParts)); - }); - - $access->expects($this->exactly(3)) - ->method('countUsers') - ->willReturnCallback(function ($filter) { - if ($filter === 'myEmailAttribute') { - return 0; - } elseif ($filter === 'mail') { - return 3; - } elseif ($filter === 'mailPrimaryAddress') { - return 17; - } - throw new \Exception('Untested filter: ' . $filter); - }); - - $result = $wizard->detectEmailAttribute()->getResultArray(); - $this->assertSame('mailPrimaryAddress', - $result['changes']['ldap_email_attr']); - } - - public function testDetectEmailAttributeFind() { - list($wizard, $configuration, $ldap, $access) - = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapEmailAttribute') { - return ''; - } else { - //for requirement checks - return 'let me pass'; - } - }); - - $access->expects($this->exactly(2)) - ->method('combineFilterWithAnd') - ->willReturnCallback(function ($filterParts) { - return str_replace('=*', '', array_pop($filterParts)); - }); - - $access->expects($this->exactly(2)) - ->method('countUsers') - ->willReturnCallback(function ($filter) { - if ($filter === 'myEmailAttribute') { - return 0; - } elseif ($filter === 'mail') { - return 3; - } elseif ($filter === 'mailPrimaryAddress') { - return 17; - } - throw new \Exception('Untested filter: ' . $filter); - }); - - $result = $wizard->detectEmailAttribute()->getResultArray(); - $this->assertSame('mailPrimaryAddress', - $result['changes']['ldap_email_attr']); - } - - public function testDetectEmailAttributeFindNothing() { - list($wizard, $configuration, $ldap, $access) - = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapEmailAttribute') { - return 'myEmailAttribute'; - } else { - //for requirement checks - return 'let me pass'; - } - }); - - $access->expects($this->exactly(3)) - ->method('combineFilterWithAnd') - ->willReturnCallback(function ($filterParts) { - return str_replace('=*', '', array_pop($filterParts)); - }); - - $access->expects($this->exactly(3)) - ->method('countUsers') - ->willReturnCallback(function ($filter) { - if ($filter === 'myEmailAttribute') { - return 0; - } elseif ($filter === 'mail') { - return 0; - } elseif ($filter === 'mailPrimaryAddress') { - return 0; - } - throw new \Exception('Untested filter: ' . $filter); - }); - - $result = $wizard->detectEmailAttribute(); - $this->assertSame(false, $result->hasChanges()); - } - - public function testCumulativeSearchOnAttributeSkipReadDN() { - // tests that there is no infinite loop, when skipping already processed - // DNs (they can be returned multiple times for multiple filters ) - list($wizard, $configuration, $ldap) = $this->getWizardAndMocks(); - - $configuration->expects($this->any()) - ->method('__get') - ->willReturnCallback(function ($name) { - if ($name === 'ldapBase') { - return ['base']; - } - return null; - }); - - $this->prepareLdapWrapperForConnections($ldap); - - $ldap->expects($this->any()) - ->method('isResource') - ->willReturnCallback(function ($res) { - return (bool)$res; - }); - - $ldap->expects($this->any()) - ->method('search') - //dummy value, usually invalid - ->willReturn(true); - - $ldap->expects($this->any()) - ->method('countEntries') - //an is_resource check will follow, so we need to return a dummy resource - ->willReturn(7); - - //5 DNs per filter means 2x firstEntry and 8x nextEntry - $ldap->expects($this->any()) - ->method('firstEntry') - //dummy value, usually invalid - ->willReturn(1); - - global $mark; - $mark = false; - // entries return order: 1, 2, 3, 4, 4, 5, 6 - $ldap->expects($this->any()) - ->method('nextEntry') - //dummy value, usually invalid - ->willReturnCallback(function ($a, $prev) { - $current = $prev + 1; - if ($current === 7) { - return false; - } - global $mark; - if ($prev === 4 && !$mark) { - $mark = true; - return 4; - } - return $current; - }); - - $ldap->expects($this->any()) - ->method('getAttributes') - //dummy value, usually invalid - ->willReturnCallback(function ($a, $entry) { - return ['cn' => [$entry], 'count' => 1]; - }); - - $ldap->expects($this->any()) - ->method('getDN') - //dummy value, usually invalid - ->willReturnCallback(function ($a, $b) { - return $b; - }); - - // The following expectations are the real test - $filters = ['f1', 'f2', '*']; - $resultArray = $wizard->cumulativeSearchOnAttribute($filters, 'cn', 0); - $this->assertSame(6, count($resultArray)); - unset($mark); - } -}