X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a6633642232efd164d4708967ab59e498fbff896..refs/pull/4191/head:/app/Http/Controllers/Auth/Saml2Controller.php diff --git a/app/Http/Controllers/Auth/Saml2Controller.php b/app/Http/Controllers/Auth/Saml2Controller.php index 8a3bf065e..b3f8e7601 100644 --- a/app/Http/Controllers/Auth/Saml2Controller.php +++ b/app/Http/Controllers/Auth/Saml2Controller.php @@ -4,11 +4,12 @@ namespace BookStack\Http\Controllers\Auth; use BookStack\Auth\Access\Saml2Service; use BookStack\Http\Controllers\Controller; +use Illuminate\Http\Request; +use Illuminate\Support\Str; class Saml2Controller extends Controller { - - protected $samlService; + protected Saml2Service $samlService; /** * Saml2Controller constructor. @@ -35,7 +36,7 @@ class Saml2Controller extends Controller */ public function logout() { - $logoutDetails = $this->samlService->logout(); + $logoutDetails = $this->samlService->logout(auth()->user()); if ($logoutDetails['id']) { session()->flash('saml2_logout_request_id', $logoutDetails['id']); @@ -50,8 +51,9 @@ class Saml2Controller extends Controller public function metadata() { $metaData = $this->samlService->metadata(); + return response()->make($metaData, 200, [ - 'Content-Type' => 'text/xml' + 'Content-Type' => 'text/xml', ]); } @@ -63,24 +65,64 @@ class Saml2Controller extends Controller { $requestId = session()->pull('saml2_logout_request_id', null); $redirect = $this->samlService->processSlsResponse($requestId) ?? '/'; + return redirect($redirect); } /** - * Assertion Consumer Service. - * Processes the SAML response from the IDP. + * Assertion Consumer Service start URL. Takes the SAMLResponse from the IDP. + * Due to being an external POST request, we likely won't have context of the + * current user session due to lax cookies. To work around this we store the + * SAMLResponse data and redirect to the processAcs endpoint for the actual + * processing of the request with proper context of the user session. + */ + public function startAcs(Request $request) + { + $samlResponse = $request->get('SAMLResponse', null); + + if (empty($samlResponse)) { + $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); + + return redirect('/login'); + } + + $acsId = Str::random(16); + $cacheKey = 'saml2_acs:' . $acsId; + cache()->set($cacheKey, encrypt($samlResponse), 10); + + return redirect()->guest('/saml2/acs?id=' . $acsId); + } + + /** + * Assertion Consumer Service process endpoint. + * Processes the SAML response from the IDP with context of the current session. + * Takes the SAML request from the cache, added by the startAcs method above. */ - public function acs() + public function processAcs(Request $request) { + $acsId = $request->get('id', null); + $cacheKey = 'saml2_acs:' . $acsId; + $samlResponse = null; + + try { + $samlResponse = decrypt(cache()->pull($cacheKey)); + } catch (\Exception $exception) { + } $requestId = session()->pull('saml2_request_id', null); - $user = $this->samlService->processAcsResponse($requestId); - if ($user === null) { + if (empty($acsId) || empty($samlResponse)) { + $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); + + return redirect('/login'); + } + + $user = $this->samlService->processAcsResponse($requestId, $samlResponse); + if (is_null($user)) { $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); + return redirect('/login'); } return redirect()->intended(); } - }