-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #116 from bcgov/test
Test
- Loading branch information
Showing
6 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
namespace App\Http\Controllers; | ||
|
||
use Illuminate\Http\Request; | ||
use Illuminate\Pagination\LengthAwarePaginator; | ||
use Illuminate\Support\Facades\Schema; | ||
use Illuminate\Support\Facades\DB; | ||
use Response; | ||
|
||
class ServiceAccountController extends Controller | ||
{ | ||
public function fetchData(Request $request) | ||
{ | ||
$tableName = $request->input('table', ''); | ||
$app = $request->input('app'); | ||
$where = $request->input('q'); | ||
$orderBy = $request->input('order'); | ||
$perPage = $request->input('per_page') ?? 5000; | ||
$connection = env('DB_DATABASE_' . strtoupper($app)); | ||
|
||
// Base query with parameter placeholders | ||
$query = DB::connection($connection)->table(strtolower($tableName)); | ||
|
||
// Add WHERE clause if provided | ||
if(isset($where)) { | ||
foreach ($where as $condition) { | ||
// Extract the column name, operator, and value from the condition | ||
$columnName = $condition['column']; | ||
$operator = $condition['operator']; | ||
$value = $condition['value']; | ||
|
||
// Add the where condition to the query | ||
$query->where($columnName, $operator, $value); | ||
} | ||
} | ||
|
||
// Add ORDER BY clause if provided | ||
if(isset($orderBy)) { | ||
$orderBy = explode("~", $orderBy); | ||
if(sizeof($orderBy) === 2) { | ||
$query->orderBy($orderBy[0], $orderBy[1]); | ||
} | ||
} | ||
|
||
// pagination parameters | ||
$currentPage = $request->input('page', 1); // Current page, default is 1 | ||
$offset = ($currentPage - 1) * $perPage; | ||
|
||
// append LIMIT and OFFSET to the query | ||
$query->limit($perPage)->offset($offset); | ||
|
||
// Execute the query with parameter bindings | ||
try { | ||
$data = $query->get(); | ||
} catch (\Exception $exception) { | ||
return response()->json(['status' => false, 'body' => $exception->errorInfo[0]]); | ||
} | ||
|
||
// Fetch total count for pagination | ||
$totalCountQuery = "SELECT COUNT(*) AS total FROM " . strtolower($tableName); | ||
$totalCount = DB::connection($connection)->selectOne($totalCountQuery); | ||
|
||
// Create pagination object | ||
$paginatedData = new LengthAwarePaginator( | ||
$data, $totalCount->total, $perPage, $currentPage | ||
); | ||
|
||
|
||
return response()->json(['status' => true, 'body' => $paginatedData]); | ||
} | ||
|
||
public function fetchTables(Request $request) | ||
{ | ||
$app = $request->input('app'); | ||
|
||
try { | ||
$tables = DB::connection(env('DB_DATABASE_' . strtoupper($app))) | ||
->select("SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema='public'"); | ||
} catch (\Exception $exception) { | ||
return response()->json(['status' => false, 'body' => $exception->errorInfo[0]], 200); | ||
} | ||
|
||
return Response::json(['status' => true, 'body' => $tables], 200); | ||
} | ||
|
||
public function fetchColumns(Request $request) | ||
{ | ||
$tableName = $request->input('table'); | ||
$app = $request->input('app'); | ||
try { | ||
$columns = Schema::connection(env('DB_DATABASE_' . strtoupper($app))) | ||
->getColumns(strtolower($tableName)); | ||
} catch (\Exception $exception) { | ||
return response()->json(['status' => false, 'body' => $exception->errorInfo[0]], 200); | ||
} | ||
|
||
return Response::json(['status' => true, 'body' => $columns], 200); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
namespace App\Http\Middleware; | ||
|
||
use Closure; | ||
use Illuminate\Http\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
class Api2Middleware | ||
{ | ||
/** | ||
* Handle an incoming request. | ||
* | ||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next | ||
*/ | ||
public function handle(Request $request, Closure $next): Response | ||
{ | ||
return $next($request); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?php | ||
|
||
namespace App\Http\Middleware; | ||
|
||
use Closure; | ||
use Firebase\JWT\ExpiredException; | ||
use Firebase\JWT\JWT; | ||
use Firebase\JWT\Key; | ||
use Illuminate\Http\Request; | ||
use Response; | ||
|
||
class ApiAuth | ||
{ | ||
/** | ||
* Handle an incoming request. | ||
* | ||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next | ||
* @param string|null ...$roles | ||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse | ||
*/ | ||
public function handle(Request $request, Closure $next, ...$roles) | ||
{ | ||
$forwardedHost = $request->headers->get('X-Forwarded-Host'); | ||
|
||
// Prevent access to the API except via the gateway | ||
if ($forwardedHost !== env('KEYCLOAK_APS_URL')) { | ||
return Response::json(['error' => 'Unauthorized.' . $forwardedHost . ',,,' . env('KEYCLOAK_APS_URL')], 403); | ||
} | ||
|
||
$token = request()->bearerToken(); | ||
if(is_null($token)){ | ||
return Response::json(['status' => false, 'error' => 'Missing token.'], 401); | ||
} | ||
$jwksUri = env('KEYCLOAK_APS_ISS') . env('KEYCLOAK_APS_CERT_PATH'); | ||
$jwksJson = file_get_contents($jwksUri); | ||
$jwksData = json_decode($jwksJson, true); | ||
$matchingKey = null; | ||
foreach ($jwksData['keys'] as $key) { | ||
if (isset($key['use']) && $key['use'] === 'sig') { | ||
$matchingKey = $key; | ||
break; | ||
} | ||
} | ||
|
||
$wrappedPk = wordwrap($matchingKey['x5c'][0], 64, "\n", true); | ||
$pk = "-----BEGIN CERTIFICATE-----\n" . $wrappedPk . "\n-----END CERTIFICATE-----"; | ||
|
||
try { | ||
$decoded = JWT::decode($token, new Key($pk, 'RS256')); | ||
} catch (ExpiredException $e) { | ||
return Response::json(['status' => false, 'error' => 'Token has expired.'], 401); | ||
} catch (\Exception $e) { | ||
return Response::json(['status' => false, 'error' => "An error occurred: " . $e->getMessage()], 401); | ||
} | ||
|
||
if(is_null($decoded)) { | ||
return Response::json(['status' => false, 'error' => "Invalid token."], 401); | ||
}else{ | ||
//only validate for accounts that we have registered | ||
if($decoded->iss === env('KEYCLOAK_APS_ISS')){ | ||
return $next($request); | ||
} | ||
} | ||
|
||
return Response::json(['status' => false, 'error' => "Generic error."], 403); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?php | ||
|
||
use App\Http\Controllers\ServiceAccountController; | ||
use Illuminate\Http\Request; | ||
use Illuminate\Support\Facades\Route; | ||
|
||
/* | ||
|-------------------------------------------------------------------------- | ||
| API Routes | ||
|-------------------------------------------------------------------------- | ||
| | ||
| Here is where you can register API routes for your application. These | ||
| routes are loaded by the RouteServiceProvider within a group which | ||
| is assigned the "api" middleware group. Enjoy building your API! | ||
| | ||
*/ | ||
Route::group(['middleware' => 'apiauth'], function () { | ||
Route::post('/fetch', [ServiceAccountController::class, 'fetchData']); | ||
Route::post('/tables', [ServiceAccountController::class, 'fetchTables']); | ||
Route::post('/columns', [ServiceAccountController::class, 'fetchColumns']); | ||
}); |