Refactor to refresh token on each call to API. Fixes #514
This commit is contained in:
parent
44a52cd3b7
commit
184cb08960
@ -217,48 +217,15 @@ class Auth extends BaseController {
|
||||
return $this->jsonResponse($response);
|
||||
}
|
||||
|
||||
public function refreshToken($request, $response) {
|
||||
$response = self::ValidateToken($request, $response);
|
||||
$status = $response->getStatusCode();
|
||||
|
||||
if ($status !== 200) {
|
||||
if ($status === 400) {
|
||||
$this->apiJson->addAlert('error',
|
||||
'Authorization header missing.');
|
||||
return $this->jsonResponse($response, $status);
|
||||
}
|
||||
|
||||
$this->apiJson->addAlert('error', 'Invalid API token.');
|
||||
return $this->jsonResponse($response, $status);
|
||||
}
|
||||
|
||||
$jwt = $request->getHeader('Authorization')[0];
|
||||
$payload = self::getJwtPayload($jwt);
|
||||
|
||||
$user = R::load('user', $payload->uid);
|
||||
$jwt = self::createJwt($user->id, (int)$payload->mul);
|
||||
|
||||
$user->active_token = $jwt;
|
||||
R::store($user);
|
||||
|
||||
$opts = R::load('useroption', $user->user_option_id);
|
||||
|
||||
$this->apiJson->setSuccess();
|
||||
$this->apiJson->addData($jwt);
|
||||
$this->apiJson->addData($this->sanitizeUser($user));
|
||||
$this->apiJson->addData($opts);
|
||||
|
||||
return $this->jsonResponse($response);
|
||||
public static function createJwt($userId, $mult = 1) {
|
||||
return JWT::encode(array(
|
||||
'exp' => time() + (60 * 30) * $mult, // 30 minutes * $mult
|
||||
'uid' => (int)$userId,
|
||||
'mul' => $mult
|
||||
), Auth::getJwtKey());
|
||||
}
|
||||
|
||||
private function sanitizeUser($user) {
|
||||
unset($user->password_hash);
|
||||
unset($user->active_token);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
private static function getJwtPayload($jwt) {
|
||||
public static function getJwtPayload($jwt) {
|
||||
try {
|
||||
$payload = JWT::decode($jwt, self::getJwtKey(), ['HS256']);
|
||||
} catch (Exception $ex) {
|
||||
@ -268,16 +235,11 @@ class Auth extends BaseController {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private static function createJwt($userId, $mult = 1) {
|
||||
// If 'remember me' feature is desired, set the multiplier higher.
|
||||
// By default, a token will expire after half an hour, but can be
|
||||
// refreshed by a call to /api/refresh.
|
||||
private function sanitizeUser($user) {
|
||||
unset($user->password_hash);
|
||||
unset($user->active_token);
|
||||
|
||||
return JWT::encode(array(
|
||||
'exp' => time() + (60 * 30) * $mult, // 30 minutes * $mult
|
||||
'uid' => (int)$userId,
|
||||
'mul' => $mult
|
||||
), Auth::getJwtKey());
|
||||
return $user;
|
||||
}
|
||||
|
||||
private static function getJwtKey() {
|
||||
|
@ -67,8 +67,13 @@ abstract class BaseController {
|
||||
return 403;
|
||||
}
|
||||
|
||||
$payload = Auth::getJwtPayload($request->getHeader('Authorization')[0]);
|
||||
$user->active_token = Auth::createJwt($user->id, $payload->mul);
|
||||
|
||||
R::store($user);
|
||||
|
||||
$this->setStrings($user->userOptionId);
|
||||
$this->apiJson->addData($request->getHeader('Authorization'));
|
||||
$this->apiJson->addData($user->active_token);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
@ -104,7 +104,6 @@ $app->get('/activity[/{type}[/{id}]]', 'Activity:getActivity'); // BoardAdmin (w
|
||||
$app->post('/login', 'Auth:login'); // Unsecured (creates JWT)
|
||||
$app->post('/logout', 'Auth:logout'); // Unsecured (clears JWT)
|
||||
$app->post('/authenticate', 'Auth:authenticate'); // Unsecured (checks JWT)
|
||||
$app->post('/refresh', 'Auth:refreshToken'); // Unsecured (checks and updates JWT)
|
||||
|
||||
$app->run();
|
||||
R::close();
|
||||
|
@ -75,9 +75,8 @@
|
||||
<h1>{{ strings['boards_noDefault'] }}</h1>
|
||||
|
||||
<p>{{ strings['boards_noDefaultMessage'] }}
|
||||
<a href="javascript:" [routerLink]="['/settings']">
|
||||
{{ strings['settings'] }}
|
||||
</a>.
|
||||
<a href="javascript:"
|
||||
[routerLink]="['/settings']">{{ strings['settings'] }}</a>.
|
||||
</p>
|
||||
|
||||
<p></p>
|
||||
|
@ -145,17 +145,15 @@ export class BoardDisplayComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
updateBoards(): void {
|
||||
this.boardService.refreshToken(() => {
|
||||
this.boardService.getBoards().subscribe((response: ApiResponse) => {
|
||||
this.boards = [];
|
||||
this.boardService.getBoards().subscribe((response: ApiResponse) => {
|
||||
this.boards = [];
|
||||
|
||||
if (response.data.length > 1) {
|
||||
this.updateBoardsList(response.data[1]);
|
||||
return;
|
||||
}
|
||||
if (response.data.length > 1) {
|
||||
this.updateBoardsList(response.data[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
});
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -180,10 +180,6 @@ export class BoardService extends ApiService {
|
||||
)
|
||||
}
|
||||
|
||||
refreshToken(callback: any): void {
|
||||
this.http.post(this.apiBase + 'refresh', {}).subscribe(() => callback());
|
||||
}
|
||||
|
||||
private async convertBoardData(boardData: any): Promise<Board> {
|
||||
if (boardData instanceof Board) {
|
||||
return boardData;
|
||||
|
@ -232,45 +232,5 @@ class AuthTest extends PHPUnit\Framework\TestCase {
|
||||
$this->assertEquals('failure', $actual->body->data->status);
|
||||
}
|
||||
|
||||
public function testRefreshToken() {
|
||||
$data = new stdClass();
|
||||
$data->username = 'admin';
|
||||
$data->password = 'admin';
|
||||
$data->remember = false;
|
||||
|
||||
$request = new RequestMock();
|
||||
$request->payload = $data;
|
||||
|
||||
Auth::CreateInitialAdmin(new LoggerMock());
|
||||
Auth::CreateJwtSigningKey();
|
||||
|
||||
$actual = $this->auth->login($request, new ResponseMock(), null);
|
||||
$this->assertEquals('success', $actual->body->data->status);
|
||||
|
||||
$jwt = $actual->body->data->data[0];
|
||||
|
||||
$this->auth = new Auth(new LoggerMock());
|
||||
$request = new RequestMock();
|
||||
$request->header = [$jwt];
|
||||
|
||||
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
|
||||
$user = R::load('user', 1);
|
||||
|
||||
$this->assertEquals('success', $actual->body->data->status);
|
||||
$this->assertEquals($user->active_token, $actual->body->data->data[0]);
|
||||
|
||||
$this->auth = new Auth(new LoggerMock());
|
||||
$request->hasHeader = false;
|
||||
|
||||
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
|
||||
$this->assertEquals('failure', $actual->body->data->status);
|
||||
|
||||
$this->auth = new Auth(new LoggerMock());
|
||||
$request = new RequestMock();
|
||||
$request->header = ['not a valid JWT'];
|
||||
|
||||
$actual = $this->auth->refreshToken($request, new ResponseMock(), null);
|
||||
$this->assertEquals('failure', $actual->body->data->status);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,10 +287,5 @@ describe('BoardService', () => {
|
||||
testCall('api/upload/asdf', 'POST', true);
|
||||
});
|
||||
|
||||
it('refreshes the API token', () => {
|
||||
service.refreshToken(() => {});
|
||||
testCall('api/refresh', 'POST');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user