1*1468a128SAndreas Gohr<?php 2*1468a128SAndreas Gohr 3*1468a128SAndreas Gohrnamespace dokuwiki\test\Remote; 4*1468a128SAndreas Gohr 5*1468a128SAndreas Gohruse dokuwiki\Remote\AccessDeniedException; 6*1468a128SAndreas Gohruse dokuwiki\Remote\ApiCall; 7*1468a128SAndreas Gohruse dokuwiki\test\mock\AuthPlugin; 8*1468a128SAndreas Gohruse dokuwiki\Extension\RemotePlugin; 9*1468a128SAndreas Gohruse dokuwiki\Remote\Api; 10*1468a128SAndreas Gohruse dokuwiki\Remote\RemoteException; 11*1468a128SAndreas Gohr 12*1468a128SAndreas Gohrclass ApiTest extends \DokuWikiTest { 13*1468a128SAndreas Gohr 14*1468a128SAndreas Gohr protected $userinfo; 15*1468a128SAndreas Gohr 16*1468a128SAndreas Gohr /** @var Api */ 17*1468a128SAndreas Gohr protected $remote; 18*1468a128SAndreas Gohr 19*1468a128SAndreas Gohr public function setUp() : void { 20*1468a128SAndreas Gohr parent::setUp(); 21*1468a128SAndreas Gohr global $plugin_controller; 22*1468a128SAndreas Gohr global $conf; 23*1468a128SAndreas Gohr global $USERINFO; 24*1468a128SAndreas Gohr global $auth; 25*1468a128SAndreas Gohr 26*1468a128SAndreas Gohr parent::setUp(); 27*1468a128SAndreas Gohr 28*1468a128SAndreas Gohr // mock plugin controller to return our test plugins 29*1468a128SAndreas Gohr $pluginManager = $this->createMock('dokuwiki\Extension\PluginController'); 30*1468a128SAndreas Gohr $pluginManager->method('getList')->willReturn(array('testplugin', 'testplugin2')); 31*1468a128SAndreas Gohr $pluginManager->method('load')->willReturnCallback( 32*1468a128SAndreas Gohr function($type, $plugin) { 33*1468a128SAndreas Gohr if($plugin == 'testplugin2') { 34*1468a128SAndreas Gohr return new remote_plugin_testplugin2(); 35*1468a128SAndreas Gohr } else { 36*1468a128SAndreas Gohr return new remote_plugin_testplugin(); 37*1468a128SAndreas Gohr } 38*1468a128SAndreas Gohr } 39*1468a128SAndreas Gohr ); 40*1468a128SAndreas Gohr $plugin_controller = $pluginManager; 41*1468a128SAndreas Gohr 42*1468a128SAndreas Gohr $conf['remote'] = 1; 43*1468a128SAndreas Gohr $conf['remoteuser'] = '!!not set!!'; 44*1468a128SAndreas Gohr $conf['useacl'] = 0; 45*1468a128SAndreas Gohr 46*1468a128SAndreas Gohr $this->userinfo = $USERINFO; 47*1468a128SAndreas Gohr $this->remote = new Api(); 48*1468a128SAndreas Gohr 49*1468a128SAndreas Gohr $auth = new AuthPlugin(); 50*1468a128SAndreas Gohr } 51*1468a128SAndreas Gohr 52*1468a128SAndreas Gohr public function tearDown() : void { 53*1468a128SAndreas Gohr global $USERINFO; 54*1468a128SAndreas Gohr $USERINFO = $this->userinfo; 55*1468a128SAndreas Gohr 56*1468a128SAndreas Gohr } 57*1468a128SAndreas Gohr 58*1468a128SAndreas Gohr public function testPluginMethods() { 59*1468a128SAndreas Gohr $methods = $this->remote->getPluginMethods(); 60*1468a128SAndreas Gohr $actual = array_keys($methods); 61*1468a128SAndreas Gohr sort($actual); 62*1468a128SAndreas Gohr $expect = array( 63*1468a128SAndreas Gohr 'plugin.testplugin.method1', 64*1468a128SAndreas Gohr 'plugin.testplugin.method2', 65*1468a128SAndreas Gohr 'plugin.testplugin.methodString', 66*1468a128SAndreas Gohr 'plugin.testplugin.method2ext', 67*1468a128SAndreas Gohr 'plugin.testplugin.publicCall', 68*1468a128SAndreas Gohr 69*1468a128SAndreas Gohr 'plugin.testplugin2.commented' 70*1468a128SAndreas Gohr ); 71*1468a128SAndreas Gohr sort($expect); 72*1468a128SAndreas Gohr $this->assertEquals($expect,$actual); 73*1468a128SAndreas Gohr } 74*1468a128SAndreas Gohr 75*1468a128SAndreas Gohr public function testPluginDescriptors() { 76*1468a128SAndreas Gohr $methods = $this->remote->getPluginMethods(); 77*1468a128SAndreas Gohr $this->assertEquals( 78*1468a128SAndreas Gohr [ 79*1468a128SAndreas Gohr 'str' => [ 80*1468a128SAndreas Gohr 'type' => 'string', 81*1468a128SAndreas Gohr 'description' => 'some more parameter description', 82*1468a128SAndreas Gohr ], 83*1468a128SAndreas Gohr 'int' => [ 84*1468a128SAndreas Gohr 'type' => 'int', 85*1468a128SAndreas Gohr 'description' => '', 86*1468a128SAndreas Gohr ], 87*1468a128SAndreas Gohr 'bool' => [ 88*1468a128SAndreas Gohr 'type' => 'bool', 89*1468a128SAndreas Gohr 'description' => '', 90*1468a128SAndreas Gohr ], 91*1468a128SAndreas Gohr 'unknown' => [ 92*1468a128SAndreas Gohr 'type' => 'string', 93*1468a128SAndreas Gohr 'description' => '', 94*1468a128SAndreas Gohr ], 95*1468a128SAndreas Gohr ], 96*1468a128SAndreas Gohr $methods['plugin.testplugin2.commented']->getArgs() 97*1468a128SAndreas Gohr ); 98*1468a128SAndreas Gohr 99*1468a128SAndreas Gohr $this->assertEquals( 100*1468a128SAndreas Gohr [ 101*1468a128SAndreas Gohr 'type' => 'array', 102*1468a128SAndreas Gohr 'description' => '', 103*1468a128SAndreas Gohr ], 104*1468a128SAndreas Gohr $methods['plugin.testplugin2.commented']->getReturn() 105*1468a128SAndreas Gohr ); 106*1468a128SAndreas Gohr 107*1468a128SAndreas Gohr $this->assertEquals(0, $methods['plugin.testplugin2.commented']->isPublic()); 108*1468a128SAndreas Gohr $this->assertStringContainsString( 109*1468a128SAndreas Gohr 'This is a dummy method', 110*1468a128SAndreas Gohr $methods['plugin.testplugin2.commented']->getSummary() 111*1468a128SAndreas Gohr ); 112*1468a128SAndreas Gohr } 113*1468a128SAndreas Gohr 114*1468a128SAndreas Gohr public function testHasAccessSuccess() 115*1468a128SAndreas Gohr { 116*1468a128SAndreas Gohr global $conf; 117*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 118*1468a128SAndreas Gohr 119*1468a128SAndreas Gohr $this->remote->ensureAccessIsAllowed(new ApiCall('time')); 120*1468a128SAndreas Gohr $this->assertTrue(true); 121*1468a128SAndreas Gohr } 122*1468a128SAndreas Gohr 123*1468a128SAndreas Gohr public function testHasAccessFailAcl() { 124*1468a128SAndreas Gohr global $conf; 125*1468a128SAndreas Gohr $conf['useacl'] = 1; 126*1468a128SAndreas Gohr 127*1468a128SAndreas Gohr $this->expectException(AccessDeniedException::class); 128*1468a128SAndreas Gohr $this->remote->ensureAccessIsAllowed(new ApiCall('time')); 129*1468a128SAndreas Gohr } 130*1468a128SAndreas Gohr 131*1468a128SAndreas Gohr public function testHasAccessSuccessAclEmptyRemoteUser() { 132*1468a128SAndreas Gohr global $conf; 133*1468a128SAndreas Gohr $conf['useacl'] = 1; 134*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 135*1468a128SAndreas Gohr 136*1468a128SAndreas Gohr $this->remote->ensureAccessIsAllowed(new ApiCall('time')); 137*1468a128SAndreas Gohr $this->assertTrue(true); 138*1468a128SAndreas Gohr } 139*1468a128SAndreas Gohr 140*1468a128SAndreas Gohr public function testHasAccessSuccessAcl() { 141*1468a128SAndreas Gohr global $conf; 142*1468a128SAndreas Gohr global $USERINFO; 143*1468a128SAndreas Gohr $conf['useacl'] = 1; 144*1468a128SAndreas Gohr $conf['remoteuser'] = '@grp,@grp2'; 145*1468a128SAndreas Gohr $USERINFO['grps'] = array('grp'); 146*1468a128SAndreas Gohr 147*1468a128SAndreas Gohr $this->remote->ensureAccessIsAllowed(new ApiCall('time')); 148*1468a128SAndreas Gohr $this->assertTrue(true); 149*1468a128SAndreas Gohr } 150*1468a128SAndreas Gohr 151*1468a128SAndreas Gohr public function testHasAccessFailAcl2() { 152*1468a128SAndreas Gohr global $conf; 153*1468a128SAndreas Gohr global $USERINFO; 154*1468a128SAndreas Gohr $conf['useacl'] = 1; 155*1468a128SAndreas Gohr $conf['remoteuser'] = '@grp'; 156*1468a128SAndreas Gohr $USERINFO['grps'] = array('grp1'); 157*1468a128SAndreas Gohr 158*1468a128SAndreas Gohr $this->expectException(AccessDeniedException::class); 159*1468a128SAndreas Gohr $this->remote->ensureAccessIsAllowed(new ApiCall('time')); 160*1468a128SAndreas Gohr } 161*1468a128SAndreas Gohr 162*1468a128SAndreas Gohr public function testIsEnabledFail1() { 163*1468a128SAndreas Gohr global $conf; 164*1468a128SAndreas Gohr $conf['remote'] = 0; 165*1468a128SAndreas Gohr $this->expectException(AccessDeniedException::class); 166*1468a128SAndreas Gohr $this->remote->ensureApiIsEnabled(); 167*1468a128SAndreas Gohr } 168*1468a128SAndreas Gohr 169*1468a128SAndreas Gohr public function testIsEnabledFail2() { 170*1468a128SAndreas Gohr global $conf; 171*1468a128SAndreas Gohr $conf['remoteuser'] = '!!not set!!'; 172*1468a128SAndreas Gohr $this->expectException(AccessDeniedException::class); 173*1468a128SAndreas Gohr $this->remote->ensureApiIsEnabled(); 174*1468a128SAndreas Gohr } 175*1468a128SAndreas Gohr 176*1468a128SAndreas Gohr public function testIsEnabledSuccess() { 177*1468a128SAndreas Gohr global $conf; 178*1468a128SAndreas Gohr $conf['remote'] = 1; 179*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 180*1468a128SAndreas Gohr $this->remote->ensureApiIsEnabled(); 181*1468a128SAndreas Gohr $this->assertTrue(true); 182*1468a128SAndreas Gohr } 183*1468a128SAndreas Gohr 184*1468a128SAndreas Gohr 185*1468a128SAndreas Gohr public function testGeneralCoreFunctionWithoutArguments() { 186*1468a128SAndreas Gohr global $conf; 187*1468a128SAndreas Gohr global $USERINFO; 188*1468a128SAndreas Gohr $conf['remote'] = 1; 189*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 190*1468a128SAndreas Gohr $conf['useacl'] = 1; 191*1468a128SAndreas Gohr $USERINFO['grps'] = array('grp'); 192*1468a128SAndreas Gohr $remoteApi = new Api(); 193*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 194*1468a128SAndreas Gohr 195*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.stringTestMethod'), 'success'); 196*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.intTestMethod'), 42); 197*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.floatTestMethod'), 3.14159265); 198*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.dateTestMethod'), 2623452346); 199*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.fileTestMethod'), 'file content'); 200*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.voidTestMethod'), null); 201*1468a128SAndreas Gohr } 202*1468a128SAndreas Gohr 203*1468a128SAndreas Gohr public function testGeneralCoreFunctionOnArgumentMismatch() { 204*1468a128SAndreas Gohr global $conf; 205*1468a128SAndreas Gohr $conf['remote'] = 1; 206*1468a128SAndreas Gohr $remoteApi = new Api(); 207*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 208*1468a128SAndreas Gohr 209*1468a128SAndreas Gohr try { 210*1468a128SAndreas Gohr $remoteApi->call('wiki.voidTestMethod', array('something')); 211*1468a128SAndreas Gohr $this->fail('Expects RemoteException to be raised'); 212*1468a128SAndreas Gohr } catch (RemoteException $th) { 213*1468a128SAndreas Gohr $this->assertEquals(-32604, $th->getCode()); 214*1468a128SAndreas Gohr } 215*1468a128SAndreas Gohr } 216*1468a128SAndreas Gohr 217*1468a128SAndreas Gohr public function testGeneralCoreFunctionWithArguments() { 218*1468a128SAndreas Gohr global $conf; 219*1468a128SAndreas Gohr global $USERINFO; 220*1468a128SAndreas Gohr $conf['remote'] = 1; 221*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 222*1468a128SAndreas Gohr $conf['useacl'] = 1; 223*1468a128SAndreas Gohr 224*1468a128SAndreas Gohr $remoteApi = new Api(); 225*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 226*1468a128SAndreas Gohr 227*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.oneStringArgMethod', array('string')), 'string'); 228*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.twoArgMethod', array('string', 1)), array('string' , 1)); 229*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.twoArgWithDefaultArg', array('string')), array('string', 'default')); 230*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('wiki.twoArgWithDefaultArg', array('string', 'another')), array('string', 'another')); 231*1468a128SAndreas Gohr } 232*1468a128SAndreas Gohr 233*1468a128SAndreas Gohr public function testGeneralCoreFunctionOnArgumentMissing() { 234*1468a128SAndreas Gohr global $conf; 235*1468a128SAndreas Gohr $conf['remote'] = 1; 236*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 237*1468a128SAndreas Gohr $remoteApi = new Api(); 238*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 239*1468a128SAndreas Gohr 240*1468a128SAndreas Gohr try { 241*1468a128SAndreas Gohr $remoteApi->call('wiki.twoArgWithDefaultArg', array()); 242*1468a128SAndreas Gohr $this->fail('Expects RemoteException to be raised'); 243*1468a128SAndreas Gohr } catch (RemoteException $th) { 244*1468a128SAndreas Gohr $this->assertEquals(-32603, $th->getCode()); 245*1468a128SAndreas Gohr } 246*1468a128SAndreas Gohr } 247*1468a128SAndreas Gohr 248*1468a128SAndreas Gohr public function testPluginCallMethods() { 249*1468a128SAndreas Gohr global $conf; 250*1468a128SAndreas Gohr global $USERINFO; 251*1468a128SAndreas Gohr $conf['remote'] = 1; 252*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 253*1468a128SAndreas Gohr $conf['useacl'] = 1; 254*1468a128SAndreas Gohr 255*1468a128SAndreas Gohr $remoteApi = new Api(); 256*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('plugin.testplugin.method1'), null); 257*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('plugin.testplugin.method2', array('string', 7)), array('string', 7, false)); 258*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('plugin.testplugin.method2ext', array('string', 7, true)), array('string', 7, true)); 259*1468a128SAndreas Gohr $this->assertEquals($remoteApi->call('plugin.testplugin.methodString'), 'success'); 260*1468a128SAndreas Gohr } 261*1468a128SAndreas Gohr 262*1468a128SAndreas Gohr public function testPluginCallMethodsOnArgumentMissing() { 263*1468a128SAndreas Gohr global $conf; 264*1468a128SAndreas Gohr $conf['remote'] = 1; 265*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 266*1468a128SAndreas Gohr $remoteApi = new Api(); 267*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 268*1468a128SAndreas Gohr 269*1468a128SAndreas Gohr try { 270*1468a128SAndreas Gohr $remoteApi->call('plugin.testplugin.method2', array()); 271*1468a128SAndreas Gohr $this->fail('Expects RemoteException to be raised'); 272*1468a128SAndreas Gohr } catch (RemoteException $th) { 273*1468a128SAndreas Gohr $this->assertEquals(-32603, $th->getCode()); 274*1468a128SAndreas Gohr } 275*1468a128SAndreas Gohr } 276*1468a128SAndreas Gohr 277*1468a128SAndreas Gohr public function testNotExistingCall() { 278*1468a128SAndreas Gohr global $conf; 279*1468a128SAndreas Gohr $conf['remote'] = 1; 280*1468a128SAndreas Gohr $conf['remoteuser'] = ''; 281*1468a128SAndreas Gohr 282*1468a128SAndreas Gohr $this->expectException(RemoteException::class); 283*1468a128SAndreas Gohr $this->expectExceptionCode(-32603); 284*1468a128SAndreas Gohr 285*1468a128SAndreas Gohr $remoteApi = new Api(); 286*1468a128SAndreas Gohr $remoteApi->call('invalid method'); // no '.' 287*1468a128SAndreas Gohr $remoteApi->call('does.not exist'); // unknown method type 288*1468a128SAndreas Gohr } 289*1468a128SAndreas Gohr 290*1468a128SAndreas Gohr public function testPublicCallCore() { 291*1468a128SAndreas Gohr global $conf; 292*1468a128SAndreas Gohr $conf['useacl'] = 1; 293*1468a128SAndreas Gohr $conf['remote'] = 1; 294*1468a128SAndreas Gohr $conf['remoteuser'] = 'restricted'; 295*1468a128SAndreas Gohr $remoteApi = new Api(); 296*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 297*1468a128SAndreas Gohr $this->assertTrue($remoteApi->call('wiki.publicCall')); 298*1468a128SAndreas Gohr } 299*1468a128SAndreas Gohr 300*1468a128SAndreas Gohr public function testPublicCallPlugin() { 301*1468a128SAndreas Gohr global $conf; 302*1468a128SAndreas Gohr $conf['useacl'] = 1; 303*1468a128SAndreas Gohr $conf['remote'] = 1; 304*1468a128SAndreas Gohr $conf['remoteuser'] = 'restricted'; 305*1468a128SAndreas Gohr $remoteApi = new Api(); 306*1468a128SAndreas Gohr $this->assertTrue($remoteApi->call('plugin.testplugin.publicCall')); 307*1468a128SAndreas Gohr } 308*1468a128SAndreas Gohr 309*1468a128SAndreas Gohr public function testPublicCallCoreDeny() { 310*1468a128SAndreas Gohr global $conf; 311*1468a128SAndreas Gohr $conf['useacl'] = 1; 312*1468a128SAndreas Gohr $this->expectException(AccessDeniedException::class); 313*1468a128SAndreas Gohr $remoteApi = new Api(); 314*1468a128SAndreas Gohr $remoteApi->getCoreMethods(new MockApiCore()); 315*1468a128SAndreas Gohr $remoteApi->call('wiki.stringTestMethod'); 316*1468a128SAndreas Gohr } 317*1468a128SAndreas Gohr 318*1468a128SAndreas Gohr public function testPublicCallPluginDeny() { 319*1468a128SAndreas Gohr global $conf; 320*1468a128SAndreas Gohr $conf['useacl'] = 1; 321*1468a128SAndreas Gohr $this->expectException(AccessDeniedException::class); 322*1468a128SAndreas Gohr $remoteApi = new Api(); 323*1468a128SAndreas Gohr $remoteApi->call('plugin.testplugin.methodString'); 324*1468a128SAndreas Gohr } 325*1468a128SAndreas Gohr} 326*1468a128SAndreas Gohr 327*1468a128SAndreas Gohr 328*1468a128SAndreas Gohr 329*1468a128SAndreas Gohr 330*1468a128SAndreas Gohrclass remote_plugin_testplugin extends RemotePlugin { 331*1468a128SAndreas Gohr function getMethods() { 332*1468a128SAndreas Gohr $methods = parent::getMethods(); // auto add all methods, then adjust 333*1468a128SAndreas Gohr 334*1468a128SAndreas Gohr $methods['method2']->limitArgs(['str', 'int']); // skip optional parameter 335*1468a128SAndreas Gohr $methods['method2ext'] = new ApiCall([$this, 'method2']); // add second call with all params 336*1468a128SAndreas Gohr $methods['publicCall']->setPublic(); // make this one public 337*1468a128SAndreas Gohr 338*1468a128SAndreas Gohr return $methods; 339*1468a128SAndreas Gohr } 340*1468a128SAndreas Gohr 341*1468a128SAndreas Gohr function method1() { return null; } 342*1468a128SAndreas Gohr function methodString() { return 'success'; } 343*1468a128SAndreas Gohr function method2($str, $int, $bool = false) { return array($str, $int, $bool); } 344*1468a128SAndreas Gohr function publicCall() {return true;} 345*1468a128SAndreas Gohr} 346*1468a128SAndreas Gohr 347*1468a128SAndreas Gohrclass remote_plugin_testplugin2 extends RemotePlugin { 348*1468a128SAndreas Gohr /** 349*1468a128SAndreas Gohr * This is a dummy method 350*1468a128SAndreas Gohr * 351*1468a128SAndreas Gohr * @param string $str some more parameter description 352*1468a128SAndreas Gohr * @param int $int 353*1468a128SAndreas Gohr * @param bool $bool 354*1468a128SAndreas Gohr * @param Object $unknown 355*1468a128SAndreas Gohr * @return array 356*1468a128SAndreas Gohr */ 357*1468a128SAndreas Gohr public function commented($str, $int, $bool, $unknown) { return array($str, $int, $bool); } 358*1468a128SAndreas Gohr 359*1468a128SAndreas Gohr private function privateMethod() {return true;} 360*1468a128SAndreas Gohr protected function protectedMethod() {return true;} 361*1468a128SAndreas Gohr public function _underscore() {return true;} 362*1468a128SAndreas Gohr} 363