]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - tests/api/ApiMiddlewareTest.php
Merge pull request #1698 from ArthurHoaro/feature/plugins-search-filter
[github/shaarli/Shaarli.git] / tests / api / ApiMiddlewareTest.php
1 <?php
2 namespace Shaarli\Api;
3
4 use Shaarli\Config\ConfigManager;
5 use Shaarli\History;
6 use Shaarli\Plugin\PluginManager;
7 use Slim\Container;
8 use Slim\Http\Environment;
9 use Slim\Http\Request;
10 use Slim\Http\Response;
11
12 /**
13 * Class ApiMiddlewareTest
14 *
15 * Test the REST API Slim Middleware.
16 *
17 * Note that we can't test a valid use case here, because the middleware
18 * needs to call a valid controller/action during its execution.
19 *
20 * @package Api
21 */
22 class ApiMiddlewareTest extends \Shaarli\TestCase
23 {
24 /**
25 * @var string datastore to test write operations
26 */
27 protected static $testDatastore = 'sandbox/datastore.php';
28
29 /**
30 * @var ConfigManager instance
31 */
32 protected $conf;
33
34 /**
35 * @var \ReferenceLinkDB instance.
36 */
37 protected $refDB = null;
38
39 /**
40 * @var Container instance.
41 */
42 protected $container;
43
44 /**
45 * Before every test, instantiate a new Api with its config, plugins and bookmarks.
46 */
47 protected function setUp(): void
48 {
49 $this->conf = new ConfigManager('tests/utils/config/configJson');
50 $this->conf->set('api.secret', 'NapoleonWasALizard');
51
52 $this->refDB = new \ReferenceLinkDB();
53 $this->refDB->write(self::$testDatastore);
54
55 $history = new History('sandbox/history.php');
56
57 $this->container = new Container();
58 $this->container['conf'] = $this->conf;
59 $this->container['history'] = $history;
60 $this->container['pluginManager'] = new PluginManager($this->conf);
61 }
62
63 /**
64 * After every test, remove the test datastore.
65 */
66 protected function tearDown(): void
67 {
68 @unlink(self::$testDatastore);
69 }
70
71 /**
72 * Invoke the middleware with a valid token
73 */
74 public function testInvokeMiddlewareWithValidToken(): void
75 {
76 $next = function (Request $request, Response $response): Response {
77 return $response;
78 };
79 $mw = new ApiMiddleware($this->container);
80 $env = Environment::mock([
81 'REQUEST_METHOD' => 'GET',
82 'REQUEST_URI' => '/echo',
83 'HTTP_AUTHORIZATION'=> 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'),
84 ]);
85 $request = Request::createFromEnvironment($env);
86 $response = new Response();
87 /** @var Response $response */
88 $response = $mw($request, $response, $next);
89
90 $this->assertEquals(200, $response->getStatusCode());
91 }
92
93 /**
94 * Invoke the middleware with a valid token
95 * Using specific Apache CGI redirected authorization.
96 */
97 public function testInvokeMiddlewareWithValidTokenFromRedirectedHeader(): void
98 {
99 $next = function (Request $request, Response $response): Response {
100 return $response;
101 };
102
103 $token = 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard');
104 $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'] = $token;
105 $mw = new ApiMiddleware($this->container);
106 $env = Environment::mock([
107 'REQUEST_METHOD' => 'GET',
108 'REQUEST_URI' => '/echo',
109 ]);
110 $request = Request::createFromEnvironment($env);
111 $response = new Response();
112 /** @var Response $response */
113 $response = $mw($request, $response, $next);
114
115 $this->assertEquals(200, $response->getStatusCode());
116 }
117
118 /**
119 * Invoke the middleware with the API disabled:
120 * should return a 401 error Unauthorized.
121 */
122 public function testInvokeMiddlewareApiDisabled()
123 {
124 $this->conf->set('api.enabled', false);
125 $mw = new ApiMiddleware($this->container);
126 $env = Environment::mock([
127 'REQUEST_METHOD' => 'GET',
128 'REQUEST_URI' => '/echo',
129 ]);
130 $request = Request::createFromEnvironment($env);
131 $response = new Response();
132 /** @var Response $response */
133 $response = $mw($request, $response, null);
134
135 $this->assertEquals(401, $response->getStatusCode());
136 $body = json_decode((string) $response->getBody());
137 $this->assertEquals('Not authorized', $body);
138 }
139
140 /**
141 * Invoke the middleware with the API disabled in debug mode:
142 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
143 */
144 public function testInvokeMiddlewareApiDisabledDebug()
145 {
146 $this->conf->set('api.enabled', false);
147 $this->conf->set('dev.debug', true);
148 $mw = new ApiMiddleware($this->container);
149 $env = Environment::mock([
150 'REQUEST_METHOD' => 'GET',
151 'REQUEST_URI' => '/echo',
152 ]);
153 $request = Request::createFromEnvironment($env);
154 $response = new Response();
155 /** @var Response $response */
156 $response = $mw($request, $response, null);
157
158 $this->assertEquals(401, $response->getStatusCode());
159 $body = json_decode((string) $response->getBody());
160 $this->assertEquals('Not authorized: API is disabled', $body->message);
161 $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
162 }
163
164 /**
165 * Invoke the middleware without a token (debug):
166 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
167 */
168 public function testInvokeMiddlewareNoTokenProvidedDebug()
169 {
170 $this->conf->set('dev.debug', true);
171 $mw = new ApiMiddleware($this->container);
172 $env = Environment::mock([
173 'REQUEST_METHOD' => 'GET',
174 'REQUEST_URI' => '/echo',
175 ]);
176 $request = Request::createFromEnvironment($env);
177 $response = new Response();
178 /** @var Response $response */
179 $response = $mw($request, $response, null);
180
181 $this->assertEquals(401, $response->getStatusCode());
182 $body = json_decode((string) $response->getBody());
183 $this->assertEquals('Not authorized: JWT token not provided', $body->message);
184 $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
185 }
186
187 /**
188 * Invoke the middleware without a secret set in settings (debug):
189 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
190 */
191 public function testInvokeMiddlewareNoSecretSetDebug()
192 {
193 $this->conf->set('dev.debug', true);
194 $this->conf->set('api.secret', '');
195 $mw = new ApiMiddleware($this->container);
196 $env = Environment::mock([
197 'REQUEST_METHOD' => 'GET',
198 'REQUEST_URI' => '/echo',
199 'HTTP_AUTHORIZATION'=> 'Bearer jwt',
200 ]);
201 $request = Request::createFromEnvironment($env);
202 $response = new Response();
203 /** @var Response $response */
204 $response = $mw($request, $response, null);
205
206 $this->assertEquals(401, $response->getStatusCode());
207 $body = json_decode((string) $response->getBody());
208 $this->assertEquals('Not authorized: Token secret must be set in Shaarli\'s administration', $body->message);
209 $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
210 }
211
212 /**
213 * Invoke the middleware with an invalid JWT token header
214 */
215 public function testInvalidJwtAuthHeaderDebug()
216 {
217 $this->conf->set('dev.debug', true);
218 $mw = new ApiMiddleware($this->container);
219 $env = Environment::mock([
220 'REQUEST_METHOD' => 'GET',
221 'REQUEST_URI' => '/echo',
222 'HTTP_AUTHORIZATION'=> 'PolarBearer jwt',
223 ]);
224 $request = Request::createFromEnvironment($env);
225 $response = new Response();
226 /** @var Response $response */
227 $response = $mw($request, $response, null);
228
229 $this->assertEquals(401, $response->getStatusCode());
230 $body = json_decode((string) $response->getBody());
231 $this->assertEquals('Not authorized: Invalid JWT header', $body->message);
232 $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
233 }
234
235 /**
236 * Invoke the middleware with an invalid JWT token (debug):
237 * should return a 401 error Unauthorized - with a specific message and a stacktrace.
238 *
239 * Note: specific JWT errors tests are handled in ApiUtilsTest.
240 */
241 public function testInvokeMiddlewareInvalidJwtDebug()
242 {
243 $this->conf->set('dev.debug', true);
244 $mw = new ApiMiddleware($this->container);
245 $env = Environment::mock([
246 'REQUEST_METHOD' => 'GET',
247 'REQUEST_URI' => '/echo',
248 'HTTP_AUTHORIZATION'=> 'Bearer jwt',
249 ]);
250 $request = Request::createFromEnvironment($env);
251 $response = new Response();
252 /** @var Response $response */
253 $response = $mw($request, $response, null);
254
255 $this->assertEquals(401, $response->getStatusCode());
256 $body = json_decode((string) $response->getBody());
257 $this->assertEquals('Not authorized: Malformed JWT token', $body->message);
258 $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
259 }
260 }