]> BookStack Code Mirror - bookstack/blobdiff - app/Http/Controllers/Auth/Saml2Controller.php
Extracted shortcut text to language files
[bookstack] / app / Http / Controllers / Auth / Saml2Controller.php
index 8a3bf065ed566b55062a184c76c7144797417060..b3f8e76015bd1b990f79efedeef99c244277d0b0 100644 (file)
@@ -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();
     }
-
 }