Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOAP binding / backend logout work in progress proposal #613

Open
wants to merge 2 commits into
base: MOODLE_39_STABLE
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .extlib/simplesamlphp/lib/SimpleSAML/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,7 @@ private function callLogoutHandlers(string $authority): void
if (empty($this->authData[$authority]['LogoutHandlers'])) {
return;
}

foreach ($this->authData[$authority]['LogoutHandlers'] as $handler) {
// verify that the logout handler is a valid function
if (!is_callable($handler)) {
Expand All @@ -746,10 +747,9 @@ private function callLogoutHandlers(string $authority): void

throw new \Exception(
'Logout handler is not a valid function: ' . $classname . '::' .
$functionname
$functionname
);
}

// call the logout handler
call_user_func($handler);
}
Expand Down
4 changes: 3 additions & 1 deletion .extlib/simplesamlphp/modules/saml/www/sp/saml2-logout.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
$dst = $idpMetadata->getEndpointPrioritizedByBinding(
'SingleLogoutService',
[
\SAML2\Constants::BINDING_SOAP,
\SAML2\Constants::BINDING_HTTP_REDIRECT,
\SAML2\Constants::BINDING_HTTP_POST
]
Expand All @@ -143,8 +144,9 @@
$dst = $dst['Location'];
}
$binding->setDestination($dst);
} else {
$lr->setDestination($dst['Location']);
}
$lr->setDestination($dst);

$binding->send($lr);
} else {
Expand Down
12 changes: 12 additions & 0 deletions classes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ public static function logout_from_idp_front_channel(): void {
require_logout();
}

public static function logout_from_idp_back_channel(): void
{
global $DB, $sp_sessionId;

if (isset($sp_sessionId)) {
$DB->delete_records('auth_saml2_kvstore', array('k' => $sp_sessionId));
$session = \SimpleSAML\Session::getSession($sp_sessionId);
\core\session\manager::kill_session($session->moodle_session_id);
}

}

/**
* SP logout callback. Called in case of normal Moodle logout.
* {@see auth::logoutpage_hook}
Expand Down
6 changes: 6 additions & 0 deletions classes/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,12 @@ public function saml_login_complete($attributes) {
$USER->site = $CFG->wwwroot;
set_moodle_cookie($USER->username);

$moodle_session_id = session_id();
$saml_session = \SimpleSAML\Session::getSessionFromRequest();
$saml_session->moodle_session_id = $moodle_session_id;
$saml_session_handler = \SimpleSAML\SessionHandler::getSessionHandler();
$saml_session_handler->saveSession($saml_session);

$wantsurl = core_login_get_return_url();
// If we are not on the page we want, then redirect to it (unless this is CLI).
if ( qualified_me() !== false && qualified_me() !== $wantsurl ) {
Expand Down
67 changes: 67 additions & 0 deletions sp/saml2-logout.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,73 @@
// user out in Moodle.
if (!is_null($session->getAuthState($saml2auth->spname))) {
$session->registerLogoutHandler($saml2auth->spname, '\auth_saml2\api', 'logout_from_idp_front_channel');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how the logut handler is registered for the case where we have a session, with some wrangling I'm hoping we can also use tehe same method to register a logout handler for the soap side of the equation.

} else {
// check if binding message exists and is logout request
try {
$binding = \SAML2\Binding::getCurrentBinding();
} catch (\Exception $e) {
// TODO: look for a specific exception
// This is dirty. Instead of checking the message of the exception, \SAML2\Binding::getCurrentBinding() should throw
// an specific exception when the binding is unknown, and we should capture that here
if ($e->getMessage() === 'Unable to find the current binding.') {
throw new \SimpleSAML\Error\Error('SLOSERVICEPARAMS', $e, 400);
} else {
throw $e; // do not ignore other exceptions!
}
}
$message = $binding->receive();
if ($message instanceof \SAML2\LogoutRequest) {
$nameId = $message->getNameId();
$sessionIndexes = $message->getSessionIndexes();

// Getting session from $nameId and $sessionIndexes
$authId = $saml2auth->spname;

assert(is_string($authId));

$store = \SimpleSAML\Store::getInstance();
if ($store === false) {
// We don't have a datastore
// TODO throw error
}

// serialize and anonymize the NameID
$strNameId = serialize($nameId);
$strNameId = sha1($strNameId);

// Normalize SessionIndexes
foreach ($sessionIndexes as &$sessionIndex) {
assert(is_string($sessionIndex));
if (strlen($sessionIndex) > 50) {
$sessionIndex = sha1($sessionIndex);
}
}

// Remove reference
unset($sessionIndex);

if ($store instanceof \SimpleSAML\Store\SQL) {
// TODO : ssp_sessions stored in db option
//$sessions = self::getSessionsSQL($store, $authId, $strNameId);
} else {
if (empty($sessionIndexes)) {
// We cannot fetch all sessions without a SQL store
return false;
}

foreach ($sessionIndexes as $sessionIndex) {
$sessionId = $store->get('saml.LogoutStore', $strNameId . ':' . $sessionIndex);
if ($sessionId === null) {
continue;
}
assert(is_string($sessionId));
$session = \SimpleSAML\Session::getSession($sessionId);
$session->registerLogoutHandler($authId, '\auth_saml2\api', 'logout_from_idp_back_channel');
$sp_sessionId = $sessionId;
continue; // only registering first session...
}
}
}
}

require('../.extlib/simplesamlphp/modules/saml/www/sp/saml2-logout.php');
Expand Down