19declare(strict_types=1);
23use GuzzleHttp\Psr7\Request;
24use GuzzleHttp\Psr7\Uri;
35 private string $cmdPart2plus =
"";
36 private bool $checkGetStatements =
true;
42 $this->cmdPart2plus =
"";
47 $this->xapiProxyResponse = $this->xapiproxy->getXapiProxyResponse();
48 $request = $this->dic->http()->request();
49 $cmdParts = $this->xapiproxy->cmdParts();
50 $this->xapiproxy->log()->debug($this->msg(var_export($cmdParts,
true)));
51 if (count($cmdParts) === 5) {
53 if ($cmd ===
"statements") {
54 $this->handleStatementsRequest($request);
55 } elseif ($cmd ===
"activities") {
56 $this->handleActivitiesRequest($request);
57 } elseif ($cmd ===
"activities/profile") {
58 $this->handleActivitiesProfileRequest($request);
59 } elseif ($cmd ===
"activities/state") {
60 $this->handleActivitiesStateRequest($request);
61 } elseif ($cmd ===
"agents") {
62 $this->handleAgentsRequest($request);
63 } elseif ($cmd ===
"agents/profile") {
64 $this->handleAgentsProfileRequest($request);
65 } elseif ($cmd ===
"about") {
66 $this->handleAboutRequest($request);
68 $this->xapiproxy->log()->debug($this->msg(
"Wrong xApi Query: " . $request->getUri()));
69 $this->xapiProxyResponse->exitBadRequest();
72 $this->xapiproxy->log()->error($this->msg(
"Wrong xApi Query: " . $request->getUri()));
73 $this->xapiProxyResponse->exitBadRequest();
77 private function msg(
string $msg): string
79 return $this->xapiproxy->msg($msg);
84 $this->xapiproxy->log()->debug($this->msg(
"handleStatementsRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
85 $method = $this->xapiproxy->method();
86 if ($method ===
"post" || $method ===
"put") {
87 $this->handlePostPutStatementsRequest($request);
88 } elseif ($method ===
"get") {
89 $this->handleGetStatementsRequest($request);
91 $this->xapiProxyResponse->exitBadRequest();
97 if ($this->xapiproxy->cmdParts()[4] ==
"") {
98 $this->xapiproxy->log()->warning($this->msg(
"unfiltered get statements requests are not allowed for security reasons"));
99 $this->xapiProxyResponse->exitBadRequest();
101 $this->xapiproxy->log()->debug($this->msg(
"handleGetStatementsRequest: " . $request->getUri()));
105 if ($this->checkGetStatements) {
109 $params = $this->dic->http()->wrapper()->query();
110 if (
$params->has(
'statementId')) {
111 $this->xapiproxy->log()->debug($this->msg(
"single statementId requests can not be secured. It is not allowed to append any additional parameter like registration or activity (tested in LL7)"));
113 $this->handleProxy($request);
115 if (
$params->has(
'activity')) {
117 $this->handleProxy($request);
119 $this->xapiproxy->log()->debug($this->msg(
"add activity: " . $obj->getActivityId()));
120 $this->cmdPart2plus .=
"&activity=" . $obj->getActivityId() .
"&related_activities=true";
122 if (!$access->hasOutcomesAccess($authToken->getUsrId())) {
135 if (
$params->has(
'registration')) {
136 $regParam =
$params->retrieve(
'registration', $this->dic->refinery()->kindlyTo()->string());
137 if ($regParam != $regUserObject) {
138 $this->xapiproxy->log()->debug($this->msg(
"wrong registration: " . $regParam .
" != " . $regUserObject));
142 $this->xapiproxy->log()->debug($this->msg(
"add registration: " . $regUserObject));
143 $this->cmdPart2plus .=
"®istration=" . $regUserObject;
149 $this->xapiProxyResponse->exitBadRequest();
151 $this->handleProxy($request);
153 }
catch (\Exception
$e) {
154 $this->xapiproxy->log()->error($this->msg(
$e->getMessage()));
160 $this->xapiproxy->log()->debug($this->msg(
"handlePostPutStatementsRequest: " . $request->getUri()));
161 $body = $request->getBody()->getContents();
162 $fakePostBody =
null;
164 $this->xapiproxy->log()->warning($this->msg(
"empty body in handlePostPutRequest"));
165 $this->handleProxy($request);
168 $this->xapiproxy->log()->debug($this->msg(
"process statements"));
169 $retArr = $this->xapiproxy->processStatements($request, $body);
170 if (is_array($retArr)) {
171 $body = json_encode($retArr[0]);
172 $fakePostBody = $retArr[1];
174 }
catch (\Exception
$e) {
175 $this->xapiproxy->log()->error($this->msg(
$e->getMessage()));
176 $this->xapiProxyResponse->exitProxyError();
179 $body = $this->xapiproxy->modifyBody($body);
180 $req =
new Request($request->getMethod(), $request->getUri(), $request->getHeaders(), $body);
181 $this->handleProxy(
$req, $fakePostBody);
182 }
catch (\Exception
$e) {
183 $this->xapiproxy->log()->error($this->msg(
$e->getMessage()));
184 $this->handleProxy($request, $fakePostBody);
193 $this->xapiproxy->log()->debug($this->msg(
"handleActivitiesRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
194 $this->handleProxy($request);
199 $this->xapiproxy->log()->debug($this->msg(
"handleActivitiesProfileRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
200 $this->handleProxy($request);
205 $this->xapiproxy->log()->debug($this->msg(
"handleActivitiesStateRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
206 $this->handleProxy($request);
211 $this->xapiproxy->log()->debug($this->msg(
"blocked handleAgentsRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
212 $this->xapiProxyResponse->exitBadRequest();
217 $this->xapiproxy->log()->debug($this->msg(
"handleAgentsProfileRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
218 $this->handleProxy($request);
223 $this->xapiproxy->log()->debug($this->msg(
"handleAboutRequest (" . $this->xapiproxy->method() .
"): " . $request->getUri()));
224 $this->handleProxy($request);
228 private function handleProxy(\Psr\Http\Message\RequestInterface $request, $fakePostBody =
null): void
230 $endpointDefault = $this->xapiproxy->getDefaultLrsEndpoint();
231 $endpointFallback = $this->xapiproxy->getFallbackLrsEndpoint();
233 $this->xapiproxy->log()->debug($this->msg(
"endpointDefault: " . $endpointDefault));
234 $this->xapiproxy->log()->debug($this->msg(
"endpointFallback: " . $endpointFallback));
236 $keyDefault = $this->xapiproxy->getDefaultLrsKey();
237 $secretDefault = $this->xapiproxy->getDefaultLrsSecret();
238 $authDefault =
'Basic ' . base64_encode($keyDefault .
':' . $secretDefault);
240 $hasFallback = ($endpointFallback !==
"");
243 $keyFallback = $this->xapiproxy->getFallbackLrsKey();
244 $secretFallback = $this->xapiproxy->getFallbackLrsSecret();
245 $authFallback =
'Basic ' . base64_encode($keyFallback .
':' . $secretFallback);
248 $cmd = $this->xapiproxy->cmdParts()[2] . $this->cmdPart2plus;
249 $upstreamDefault = $endpointDefault . $cmd;
250 $body = $request->getBody()->getContents();
253 $responseDefault = $this->sendCurlRequest($upstreamDefault, $authDefault, $request->getMethod(), $body);
256 $responseFallback =
null;
258 $upstreamFallback = $endpointFallback . $cmd;
259 $responseFallback = $this->sendCurlRequest($upstreamFallback, $authFallback, $request->getMethod(), $body);
263 $defaultOk = $this->xapiProxyResponse->checkResponse($responseDefault, $endpointDefault);
264 $fallbackOk = $hasFallback ? $this->xapiProxyResponse->checkResponse($responseFallback, $endpointFallback) :
false;
268 $this->xapiProxyResponse->handleResponse($request, $responseDefault, $fakePostBody);
269 }
catch (\Exception
$e) {
270 $this->xapiProxyResponse->exitProxyError();
272 } elseif ($fallbackOk) {
274 $this->xapiProxyResponse->handleResponse($request, $responseFallback, $fakePostBody);
275 }
catch (\Exception
$e) {
276 $this->xapiProxyResponse->exitProxyError();
279 $this->xapiProxyResponse->exitResponseError();
283 private function sendCurlRequest(
string $url,
string $authHeader,
string $method,
string $body =
''): \GuzzleHttp\Psr7\Response
285 $ch = curl_init(
$url);
287 "Authorization: $authHeader",
288 "X-Experience-API-Version: 1.0.3",
289 "Accept: application/json",
290 "Content-Type: application/json"
293 curl_setopt_array($ch, [
294 CURLOPT_RETURNTRANSFER =>
true,
295 CURLOPT_FOLLOWLOCATION =>
true,
296 CURLOPT_CONNECTTIMEOUT => 10,
297 CURLOPT_TIMEOUT => 30,
298 CURLOPT_SSL_VERIFYPEER =>
true,
299 CURLOPT_HTTPHEADER => $headers,
300 CURLOPT_CUSTOMREQUEST => strtoupper($method),
303 if (in_array(strtoupper($method), [
'POST',
'PUT',
'PATCH'])) {
304 curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
307 $rawBody = curl_exec($ch);
308 $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
309 $curlError = curl_error($ch);
313 $this->xapiproxy->log()->error(
"cURL error for $url: $curlError");
317 return new \GuzzleHttp\Psr7\Response($statusCode, [], $rawBody);
320 private function createProxyRequest(\Psr\Http\Message\RequestInterface $request, \GuzzleHttp\Psr7\Uri $uri,
string $auth,
string $body): \GuzzleHttp\Psr7\Request
323 'Cache-Control' =>
'no-cache, no-store, must-revalidate',
324 'Authorization' => $auth
327 if ($request->hasHeader(
'X-Experience-API-Version')) {
328 $headers[
'X-Experience-API-Version'] = $request->getHeader(
'X-Experience-API-Version');
331 if ($request->hasHeader(
'Referrer')) {
332 $headers[
'Referrer'] = $request->getHeader(
'Referrer');
335 if ($request->hasHeader(
'Content-Type')) {
336 $headers[
'Content-Type'] = $request->getHeader(
'Content-Type');
339 if ($request->hasHeader(
'Origin')) {
340 $headers[
'Origin'] = $request->getHeader(
'Origin');
343 if ($request->hasHeader(
'Content-Length')) {
344 $contentLength = $request->getHeader(
'Content-Length');
345 if (is_array($contentLength) && $contentLength[0] ===
'') {
346 $contentLength = array(0);
347 } elseif ($contentLength ===
'') {
348 $contentLength = array(0);
350 $headers[
'Content-Length'] = $contentLength;
353 if ($request->hasHeader(
'Connection')) {
354 $headers[
'Connection'] = $request->getHeader(
'Connection');
359 $req =
new Request(strtoupper($request->getMethod()), $uri, $headers, $body);
Customizing of pimple-DIC for ILIAS.
__construct(XapiProxy $xapiproxy)
XapiProxyResponse $xapiProxyResponse
handleActivitiesStateRequest(\Psr\Http\Message\RequestInterface $request)
handlePostPutStatementsRequest(\Psr\Http\Message\RequestInterface $request)
handleAboutRequest(\Psr\Http\Message\RequestInterface $request)
handleStatementsRequest(\Psr\Http\Message\RequestInterface $request)
handleActivitiesProfileRequest(\Psr\Http\Message\RequestInterface $request)
sendCurlRequest(string $url, string $authHeader, string $method, string $body='')
handleActivitiesRequest(\Psr\Http\Message\RequestInterface $request)
handleGetStatementsRequest(\Psr\Http\Message\RequestInterface $request)
handleAgentsRequest(\Psr\Http\Message\RequestInterface $request)
handleAgentsProfileRequest(\Psr\Http\Message\RequestInterface $request)
handleProxy(\Psr\Http\Message\RequestInterface $request, $fakePostBody=null)
createProxyRequest(\Psr\Http\Message\RequestInterface $request, \GuzzleHttp\Psr7\Uri $uri, string $auth, string $body)
static getInstance(ilObjCmiXapi $object)
static getInstanceByToken(string $token)
static getCMI5RegistrationFromAuthToken(ilCmiXapiAuthToken $authToken)
static getRegistrationFromAuthToken(ilCmiXapiAuthToken $authToken)
static getInstance(int $a_id=0, bool $a_reference=true)
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
catch(\Exception $e) $req