diff --git a/README.md b/README.md index a3daa35..003c965 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ Event::listen(\Slides\Saml2\Events\SignedIn::class, function (\Slides\Saml2\Even $user = // find user by ID or attribute + \Slides\Saml2\Session::store($samlUser->getTenant(), $samlUser); + // Login a user. Auth::login($user); }); @@ -165,8 +167,8 @@ There are two ways the user can logout: - By logging out in your app. In this case you SHOULD notify the IdP first so it'll close the global session. - By logging out of the global SSO Session. In this case the IdP will notify you on `/saml2/{uuid}/slo` endpoint (already provided). -For the first case, call `Saml2Auth::logout();` or redirect the user to the route `saml.logout` which does just that. -Do not close the session immediately as you need to receive a response confirmation from the IdP (redirection). +For the first case, call `Session::logout();` or redirect the user to the route `saml.logout` which does just that. +Do not close the Laravel session immediately as you need to receive a response confirmation from the IdP (redirection). That response will be handled by the library at `/saml2/sls` and will fire an event for you to complete the operation. For the second case you will only receive the event. Both cases receive the same event. diff --git a/src/Session.php b/src/Session.php new file mode 100644 index 0000000..08f32e3 --- /dev/null +++ b/src/Session.php @@ -0,0 +1,105 @@ +tenants = $tenants; + $this->builder = $builder; + } + + public function exists(): bool + { + return Cookie::has('saml_tenant_id'); + } + + public function store(Tenant $tenant, Saml2User $samlUser): void + { + Cookie::queue(cookie()->make('saml_tenant_id', $tenant->id, config('session.lifetime'))); + Cookie::queue(cookie()->make('saml_session_id', $samlUser->getSessionIndex(), config('session.lifetime'))); + Cookie::queue(cookie()->make('saml_name_id', $samlUser->getNameId(), config('session.lifetime'))); + } + + public function clear(): void + { + Cookie::queue(cookie()->forget('saml_tenant_id')); + Cookie::queue(cookie()->forget('saml_session_id')); + Cookie::queue(cookie()->forget('saml_name_id')); + } + + /** + * Generates the redirect url to initiate a global session + * sign out for a user with the IdP. + */ + public function logout(): ?RedirectResponse + { + if (!$this->exists()) { + return null; + } + + $tenant = $this->resolveTenant(); + if (empty($tenant)) { + return null; + } + + $this->builder + ->withTenant($tenant) + ->bootstrap(); + + try { + $sloUrl = Auth::logout( + config('saml2.logoutRoute'), + Cookie::get('saml_name_id'), + Cookie::get('saml_session_id'), + null, + true + ); + } catch (OneLoginError $e) { + report($e); + return null; + } + + return redirect($sloUrl)->withHeaders([ + 'Pragma' => 'no-cache', + 'Cache-Control' => 'no-cache, must-revalidate', + ]); + } + + /** + * Resolve a tenant from the session. + */ + protected function resolveTenant(): ?Tenant + { + $id = Cookie::get('saml_tenant_id'); + if (empty($id)) { + return null; + } + + return $this->tenants->findById($id); + } +}