| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | namespace BookStack\Access\Controllers; | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Access\Saml2Service; | 
					
						
							| 
									
										
										
										
											2023-05-19 03:53:39 +08:00
										 |  |  | use BookStack\Http\Controller; | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  | use Illuminate\Http\Request; | 
					
						
							| 
									
										
										
										
											2021-11-15 05:13:24 +08:00
										 |  |  | use Illuminate\Support\Str; | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Saml2Controller extends Controller | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-09-22 23:54:27 +08:00
										 |  |  |     protected Saml2Service $samlService; | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Saml2Controller constructor. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __construct(Saml2Service $samlService) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->samlService = $samlService; | 
					
						
							| 
									
										
										
										
											2020-02-02 21:10:21 +08:00
										 |  |  |         $this->middleware('guard:saml2'); | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Start the login flow via SAML2. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function login() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $loginDetails = $this->samlService->login(); | 
					
						
							|  |  |  |         session()->flash('saml2_request_id', $loginDetails['id']); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return redirect($loginDetails['url']); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-17 23:40:36 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Start the logout flow via SAML2. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function logout() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-10-24 00:26:01 +08:00
										 |  |  |         $logoutDetails = $this->samlService->logout(auth()->user()); | 
					
						
							| 
									
										
										
										
											2019-11-17 23:40:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if ($logoutDetails['id']) { | 
					
						
							|  |  |  |             session()->flash('saml2_logout_request_id', $logoutDetails['id']); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return redirect($logoutDetails['url']); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |     /* | 
					
						
							|  |  |  |      * Get the metadata for this SAML2 service provider. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function metadata() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $metaData = $this->samlService->metadata(); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |         return response()->make($metaData, 200, [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Content-Type' => 'text/xml', | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |         ]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Single logout service. | 
					
						
							|  |  |  |      * Handle logout requests and responses. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function sls() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-11-17 23:40:36 +08:00
										 |  |  |         $requestId = session()->pull('saml2_logout_request_id', null); | 
					
						
							|  |  |  |         $redirect = $this->samlService->processSlsResponse($requestId) ?? '/'; | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-17 23:40:36 +08:00
										 |  |  |         return redirect($redirect); | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |      * 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. | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |     public function startAcs(Request $request) | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |         $samlResponse = $request->get('SAMLResponse', null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (empty($samlResponse)) { | 
					
						
							|  |  |  |             $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); | 
					
						
							| 
									
										
										
										
											2021-10-20 20:40:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |             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 processAcs(Request $request) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $acsId = $request->get('id', null); | 
					
						
							|  |  |  |         $cacheKey = 'saml2_acs:' . $acsId; | 
					
						
							|  |  |  |         $samlResponse = null; | 
					
						
							| 
									
										
										
										
											2021-10-20 20:40:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |         try { | 
					
						
							|  |  |  |             $samlResponse = decrypt(cache()->pull($cacheKey)); | 
					
						
							| 
									
										
										
										
											2021-10-20 20:40:27 +08:00
										 |  |  |         } catch (\Exception $exception) { | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-11-15 05:13:24 +08:00
										 |  |  |         $requestId = session()->pull('saml2_request_id', null); | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (empty($acsId) || empty($samlResponse)) { | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |             $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); | 
					
						
							| 
									
										
										
										
											2021-10-20 20:40:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |             return redirect('/login'); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-20 20:30:45 +08:00
										 |  |  |         $user = $this->samlService->processAcsResponse($requestId, $samlResponse); | 
					
						
							|  |  |  |         if (is_null($user)) { | 
					
						
							|  |  |  |             $this->showErrorNotification(trans('errors.saml_fail_authed', ['system' => config('saml2.name')])); | 
					
						
							| 
									
										
										
										
											2021-10-20 20:40:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-17 21:26:43 +08:00
										 |  |  |             return redirect('/login'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return redirect()->intended(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |