diff options
author | VirtualTam <virtualtam@flibidi.net> | 2017-01-07 22:23:47 +0100 |
---|---|---|
committer | VirtualTam <virtualtam+github@flibidi.net> | 2017-01-15 13:41:04 +0100 |
commit | 63ef549749fac9d0e302842f06e7794d1daabc13 (patch) | |
tree | 0ff9dc942d61ca50a251a900f1b923ac8ff39cda | |
parent | 37ab940599d40472c5b4a3bbe5a10515046c64ee (diff) | |
download | Shaarli-63ef549749fac9d0e302842f06e7794d1daabc13.tar.gz Shaarli-63ef549749fac9d0e302842f06e7794d1daabc13.tar.zst Shaarli-63ef549749fac9d0e302842f06e7794d1daabc13.zip |
API: expect JWT in the Authorization header
Relates to https://github.com/shaarli/Shaarli/pull/731
Added:
- require the presence of the 'Authorization' header
Changed:
- use the HTTP Bearer Token authorization schema
See:
- https://jwt.io/introduction/#how-do-json-web-tokens-work-
- https://tools.ietf.org/html/rfc6750
- http://security.stackexchange.com/q/108662
Signed-off-by: VirtualTam <virtualtam@flibidi.net>
-rw-r--r-- | application/api/ApiMiddleware.php | 11 | ||||
-rw-r--r-- | tests/api/ApiMiddlewareTest.php | 29 |
2 files changed, 34 insertions, 6 deletions
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php index 162e88e0..522091ca 100644 --- a/application/api/ApiMiddleware.php +++ b/application/api/ApiMiddleware.php | |||
@@ -98,8 +98,7 @@ class ApiMiddleware | |||
98 | * @throws ApiAuthorizationException The token couldn't be validated. | 98 | * @throws ApiAuthorizationException The token couldn't be validated. |
99 | */ | 99 | */ |
100 | protected function checkToken($request) { | 100 | protected function checkToken($request) { |
101 | $jwt = $request->getHeaderLine('jwt'); | 101 | if (! $request->hasHeader('Authorization')) { |
102 | if (empty($jwt)) { | ||
103 | throw new ApiAuthorizationException('JWT token not provided'); | 102 | throw new ApiAuthorizationException('JWT token not provided'); |
104 | } | 103 | } |
105 | 104 | ||
@@ -107,7 +106,13 @@ class ApiMiddleware | |||
107 | throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); | 106 | throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); |
108 | } | 107 | } |
109 | 108 | ||
110 | ApiUtils::validateJwtToken($jwt, $this->conf->get('api.secret')); | 109 | $authorization = $request->getHeaderLine('Authorization'); |
110 | |||
111 | if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { | ||
112 | throw new ApiAuthorizationException('Invalid JWT header'); | ||
113 | } | ||
114 | |||
115 | ApiUtils::validateJwtToken($matches[1], $this->conf->get('api.secret')); | ||
111 | } | 116 | } |
112 | 117 | ||
113 | /** | 118 | /** |
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php index 4d4dd9b9..d9753b1d 100644 --- a/tests/api/ApiMiddlewareTest.php +++ b/tests/api/ApiMiddlewareTest.php | |||
@@ -143,7 +143,7 @@ class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase | |||
143 | $env = Environment::mock([ | 143 | $env = Environment::mock([ |
144 | 'REQUEST_METHOD' => 'GET', | 144 | 'REQUEST_METHOD' => 'GET', |
145 | 'REQUEST_URI' => '/echo', | 145 | 'REQUEST_URI' => '/echo', |
146 | 'HTTP_JWT'=> 'jwt', | 146 | 'HTTP_AUTHORIZATION'=> 'Bearer jwt', |
147 | ]); | 147 | ]); |
148 | $request = Request::createFromEnvironment($env); | 148 | $request = Request::createFromEnvironment($env); |
149 | $response = new Response(); | 149 | $response = new Response(); |
@@ -157,7 +157,30 @@ class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase | |||
157 | } | 157 | } |
158 | 158 | ||
159 | /** | 159 | /** |
160 | * Invoke the middleware without an invalid JWT token (debug): | 160 | * Invoke the middleware with an invalid JWT token header |
161 | */ | ||
162 | public function testInvalidJwtAuthHeaderDebug() | ||
163 | { | ||
164 | $this->conf->set('dev.debug', true); | ||
165 | $mw = new ApiMiddleware($this->container); | ||
166 | $env = Environment::mock([ | ||
167 | 'REQUEST_METHOD' => 'GET', | ||
168 | 'REQUEST_URI' => '/echo', | ||
169 | 'HTTP_AUTHORIZATION'=> 'PolarBearer jwt', | ||
170 | ]); | ||
171 | $request = Request::createFromEnvironment($env); | ||
172 | $response = new Response(); | ||
173 | /** @var Response $response */ | ||
174 | $response = $mw($request, $response, null); | ||
175 | |||
176 | $this->assertEquals(401, $response->getStatusCode()); | ||
177 | $body = json_decode((string) $response->getBody()); | ||
178 | $this->assertEquals('Not authorized: Invalid JWT header', $body->message); | ||
179 | $this->assertContains('ApiAuthorizationException', $body->stacktrace); | ||
180 | } | ||
181 | |||
182 | /** | ||
183 | * Invoke the middleware with an invalid JWT token (debug): | ||
161 | * should return a 401 error Unauthorized - with a specific message and a stacktrace. | 184 | * should return a 401 error Unauthorized - with a specific message and a stacktrace. |
162 | * | 185 | * |
163 | * Note: specific JWT errors tests are handled in ApiUtilsTest. | 186 | * Note: specific JWT errors tests are handled in ApiUtilsTest. |
@@ -169,7 +192,7 @@ class ApiMiddlewareTest extends \PHPUnit_Framework_TestCase | |||
169 | $env = Environment::mock([ | 192 | $env = Environment::mock([ |
170 | 'REQUEST_METHOD' => 'GET', | 193 | 'REQUEST_METHOD' => 'GET', |
171 | 'REQUEST_URI' => '/echo', | 194 | 'REQUEST_URI' => '/echo', |
172 | 'HTTP_JWT'=> 'bad jwt', | 195 | 'HTTP_AUTHORIZATION'=> 'Bearer jwt', |
173 | ]); | 196 | ]); |
174 | $request = Request::createFromEnvironment($env); | 197 | $request = Request::createFromEnvironment($env); |
175 | $response = new Response(); | 198 | $response = new Response(); |