Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 60
AbstractApiController
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 15
1260
0.00% covered (danger)
0.00%
0 / 60
 __construct
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 8
 checkExternalAccessRights
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 6
 fileResponse
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 response
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getResponseFromService
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 postResponseFromService
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 putResponseFromService
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 deleteResponseFromService
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getResponseFromExternal
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 postResponseFromExternal
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 putResponseFromExternal
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 deleteResponseFromExternal
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 createRequestObject
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 createExternalRequestObject
0.00% covered (danger)
0.00%
0 / 1
132
0.00% covered (danger)
0.00%
0 / 15
 respond
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 12
1<?php
2
3namespace Qmp\Laravel\ApiGateway\Controllers;
4
5use App\Http\Controllers\Controller;
6use Illuminate\Http\Exceptions\HttpResponseException;
7use Illuminate\Support\Facades\Log;
8use Illuminate\Support\Facades\Route;
9use Illuminate\Support\Str;
10use Qmp\Laravel\ApiFilterRequest\Middleware\FilterRequest;
11
12use Qmp\Laravel\MicroService\Client\Client;
13use Qmp\Laravel\MicroService\Client\Tools\Request;
14use Qmp\Laravel\MicroService\Client\Tools\Response;
15
16use Qmp\Laravel\MicroService\Middleware\JsonResponse;
17
18abstract class AbstractApiController extends Controller
19{
20    protected $externalAuthAcceptedMethods = [];
21
22    protected $methodsWithoutJsonMiddleware = [];
23
24    /**
25     * AbstractApiController constructor.
26     */
27    public function __construct()
28    {
29        if (!\App::runningInConsole() && request()->header('x-auth-type') !== 'external' && request()->header('x-auth-type') !== 'system') {
30            $currentRoute = str_replace(['latest.', config('api_gateway.latest') . '.'], '', Route::currentRouteName());
31            if(!in_array($currentRoute, config('api_gateway.no_permission'))) {
32                $this->middleware("perm:$currentRoute");
33            }
34        }
35
36        $this->middleware(FilterRequest::class)->only('indexFiltered');
37        $this->middleware(JsonResponse::class)->except($this->methodsWithoutJsonMiddleware);
38
39        $this->checkExternalAccessRights();
40    }
41
42    protected function checkExternalAccessRights()
43    {
44        if (!\App::runningInConsole()) {
45            [$class, $method] = explode('@', class_basename(Route::currentRouteAction()));
46            if (request()->header('x-auth-type') === 'external' && !in_array($method, $this->externalAuthAcceptedMethods)) {
47                Log::debug('External access from forbidden route : ' . Route::currentRouteAction());
48                throw new HttpResponseException(response()->json(['status' => 'ko', 'error' => 'Unauthenticated'], 403));
49            }
50        }
51    }
52
53    /**
54     * @param $filename
55     * @param int $code
56     * @return $this
57     */
58    protected function fileResponse($filename, int $code = 200)
59    {
60        return response()->download($filename, basename($filename), ['content-type' => mime_content_type($filename), 'Content-encoding' => 'none'])->setStatusCode($code);
61    }
62
63    /**
64     * @param $data
65     * @param int $code
66     * @return $this
67     */
68    protected function response($data, int $code = 200)
69    {
70        return response()->json($data)->setStatusCode($code);
71    }
72
73    /**
74     * @param string $dockerServiceHostname
75     * @param string $path
76     * @param array $parameters
77     * @return Response
78     */
79    protected function getResponseFromService(string $dockerServiceHostname, string $path, array $parameters = []): Response
80    {
81        $request = $this->createRequestObject($dockerServiceHostname, $path, $parameters);
82        return Client::get($request);
83    }
84
85    /**
86     * @param string $dockerServiceHostname
87     * @param string $path
88     * @param array $parameters
89     * @return Response
90     */
91    protected function postResponseFromService(string $dockerServiceHostname, string $path, array $parameters = []): Response
92    {
93        $request = $this->createRequestObject($dockerServiceHostname, $path, $parameters);
94        return Client::post($request);
95    }
96
97    /**
98     * @param string $dockerServiceHostname
99     * @param string $path
100     * @param array $parameters
101     * @return Response
102     */
103    protected function putResponseFromService(string $dockerServiceHostname, string $path, array $parameters = []): Response
104    {
105        $request = $this->createRequestObject($dockerServiceHostname, $path, $parameters);
106        return Client::put($request);
107    }
108
109    /**
110     * @param string $dockerServiceHostname
111     * @param string $path
112     * @param array $parameters
113     * @return Response
114     */
115    protected function deleteResponseFromService(string $dockerServiceHostname, string $path, array $parameters = []): Response
116    {
117        $request = $this->createRequestObject($dockerServiceHostname, $path, $parameters);
118        return Client::delete($request);
119    }
120
121    /**
122     * @param string $url
123     * @param string $path
124     * @param array $parameters
125     * @return Response
126     */
127    protected function getResponseFromExternal(string $url, string $path, array $parameters = []): Response
128    {
129        $request = $this->createExternalRequestObject($url, $path, $parameters);
130        return Client::get($request);
131    }
132
133    /**
134     * @param string $url
135     * @param string $path
136     * @param array $parameters
137     * @return Response
138     */
139    protected function postResponseFromExternal(string $url, string $path, array $parameters = []): Response
140    {
141        $request = $this->createExternalRequestObject($url, $path, $parameters);
142        return Client::post($request);
143    }
144
145    /**
146     * @param string $url
147     * @param string $path
148     * @param array $parameters
149     * @return Response
150     */
151    protected function putResponseFromExternal(string $url, string $path, array $parameters = []): Response
152    {
153        $request = $this->createExternalRequestObject($url, $path, $parameters);
154        return Client::put($request);
155    }
156
157    /**
158     * @param string $url
159     * @param string $path
160     * @param array $parameters
161     * @return Response
162     */
163    protected function deleteResponseFromExternal(string $url, string $path, array $parameters = []): Response
164    {
165        $request = $this->createExternalRequestObject($url, $path, $parameters);
166        return Client::delete($request);
167    }
168
169    /**
170     * @param string $dockerServiceHostname
171     * @param string $path
172     * @param array $parameters
173     * @return Request
174     */
175    protected function createRequestObject(string $dockerServiceHostname, string $path, array $parameters = []): Request
176    {
177        return $this->createExternalRequestObject('http://' . $dockerServiceHostname, 'api/' . $path, $parameters);
178    }
179
180    /**
181     * @param string $dockerServiceHostname
182     * @param string $path
183     * @param array $parameters
184     * @return Request
185     */
186    protected function createExternalRequestObject(string $url, string $path, array $parameters = []): Request
187    {
188        $request = new Request();
189        $request->setUrl($url)
190            ->setPath($path);
191
192        if (!empty($parameters['query']) && is_array($parameters['query'])) {
193            $request->setQuery($parameters['query']);
194        }
195        if (!empty($parameters['body']) && is_array($parameters['body'])) {
196            $request->setBody($parameters['body']);
197        }
198        if (!empty($parameters['multipart']) && is_array($parameters['multipart'])) {
199            $request->setJsonBody(null);
200            $request->setMultipart($parameters['multipart']);
201        }
202        if (!empty($parameters['timeout']) && is_int($parameters['timeout'])) {
203            $request->setTimeout($parameters['timeout']);
204        }
205        if (!empty($parameters['headers']) && is_array($parameters['headers'])) {
206            $request->setHeaders($parameters['headers']);
207        }
208
209        return $request;
210    }
211
212    /**
213     * @param Response $response
214     * @param int $validCodeReceived
215     * @param int $errorCodeReturn
216     * @param string $errorMessageReturn
217     * @return \Illuminate\Http\JsonResponse|mixed|null
218     */
219    protected function respond(Response $response, $validCodeReceived = 200, $errorCodeReturn = 401, $errorMessageReturn = 'Unauthorized')
220    {
221        if (Str::startsWith($response->code, '2')) {
222            return $response->content;
223        }
224
225        if ($response->code === $validCodeReceived) {
226            return $response->content;
227        }
228
229        Log::debug('API Gateaway Response mismatch : ' . var_export([
230            "Expected" => $validCodeReceived,
231            "Given" => $response->code,
232            "Message" => $response->body
233        ], true));
234
235        if ($response->code === $errorCodeReturn) {
236            return $this->response($response->content, $errorCodeReturn);
237        }
238
239        return $this->response(['error' => $errorMessageReturn], $errorCodeReturn);
240    }
241}