forked from extern/egroupware
SAML/Shibboleth with multiple IdP or optional on regular login page
This commit is contained in:
parent
06d6887744
commit
4c131c1866
@ -57,6 +57,14 @@ egw_LAB.wait(function()
|
||||
{ "svg": egw_webserverUrl+"/api/templates/default/images/login_discourse.svg", "url": "https://help.egroupware.org" },
|
||||
{ "svg": egw_webserverUrl+"/api/templates/default/images/login_github.svg", "url": "https://github.com/EGroupware/egroupware" }
|
||||
]);
|
||||
|
||||
// automatic submit of SAML IdP selection
|
||||
jQuery('select.onChangeSubmit').on('change', function() {
|
||||
if (this.value) {
|
||||
this.form.method = 'GET';
|
||||
this.form.submit();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -70,6 +70,7 @@ $setup_info['api']['hooks']['vfs_rmdir'] = 'EGroupware\\Api\\Vfs\\Sharing::vfsUp
|
||||
|
||||
// hook to update SimpleSAMLphp config
|
||||
$setup_info['api']['hooks']['setup_config'] = \EGroupware\Api\Auth\Saml::class.'::setupConfig';
|
||||
$setup_info['api']['hooks']['login_discovery'] = \EGroupware\Api\Auth\Saml::class.'::discovery';
|
||||
|
||||
// installation checks
|
||||
$setup_info['api']['check_install'] = array(
|
||||
|
@ -53,20 +53,38 @@ class Auth
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Backend $type =null default is type from session / auth or login, or if not set config
|
||||
* @throws Exception\AssertionFailed if backend is not an Auth\Backend
|
||||
*/
|
||||
function __construct()
|
||||
function __construct($type=null)
|
||||
{
|
||||
$this->backend = self::backend();
|
||||
$this->backend = self::backend($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current backend
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function backendType()
|
||||
{
|
||||
return Cache::getSession(__CLASS__, 'backend');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instanciate a backend
|
||||
*
|
||||
* @param Backend $type =null
|
||||
* Type will be stored in session, to automatic use the same type eg. for conditional use of SAML.
|
||||
*
|
||||
* @param Backend $type =null default is type from session / auth or login, or if not set config
|
||||
* @return Auth\Backend|Auth\BackendSSO
|
||||
*/
|
||||
static function backend($type=null)
|
||||
{
|
||||
if (is_null($type))
|
||||
{
|
||||
$type = Cache::getSession(__CLASS__, 'backend') ?: null;
|
||||
}
|
||||
// do we have a hostname specific auth type set
|
||||
if (is_null($type) && !empty($GLOBALS['egw_info']['server']['auth_type_host']) &&
|
||||
Header\Http::host() === $GLOBALS['egw_info']['server']['auth_type_hostname'])
|
||||
@ -88,18 +106,49 @@ class Auth
|
||||
{
|
||||
throw new Exception\AssertionFailed("Auth backend class $backend_class is NO EGroupware\\Api\Auth\\Backend!");
|
||||
}
|
||||
Cache::setSession(__CLASS__, 'backend', $type);
|
||||
|
||||
return $backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt a SSO login
|
||||
*
|
||||
* A different then the default backend can be selected by setting request parameter auth to the backend or
|
||||
* setting "auth=$backend" to an arbitrary value eg. with a submit button named like that.
|
||||
* To secure this behavior the server config "${auth}_discovery" has to be set (to a non-empty value)!
|
||||
*
|
||||
* @return string sessionid on successful login or null
|
||||
* @throws Exception\AssertionFailed
|
||||
*/
|
||||
static function login()
|
||||
{
|
||||
$backend = self::backend();
|
||||
if (!empty($_REQUEST['auth']))
|
||||
{
|
||||
$type = $_REQUEST['auth'];
|
||||
}
|
||||
elseif (($auth = array_filter($_REQUEST, function($key)
|
||||
{
|
||||
return substr($key, 0, 5) === 'auth=';
|
||||
}, ARRAY_FILTER_USE_KEY)))
|
||||
{
|
||||
$type = substr(key($auth), 5);
|
||||
}
|
||||
// to not allow enabling all sort of auth plugins by simply calling login.php?auth=xyz we require the
|
||||
// plugin to be enabled via "${auth}_discovery" server config
|
||||
if (!empty($type) && empty($GLOBALS['egw_info']['server'][$type.'_discovery']))
|
||||
{
|
||||
$type = null;
|
||||
}
|
||||
|
||||
// now we need a (not yet authenticated) session so SAML / auth source selected "survives" eg. the SAML redirects
|
||||
if (!empty($type) && !Session::get_sessionid())
|
||||
{
|
||||
session_start();
|
||||
Session::egw_setcookie(Session::EGW_SESSION_NAME, session_id());
|
||||
}
|
||||
|
||||
$backend = self::backend($type ?? null);
|
||||
|
||||
return $backend instanceof Auth\BackendSSO ? $backend->login() : null;
|
||||
}
|
||||
@ -110,11 +159,9 @@ class Auth
|
||||
* @return null
|
||||
* @throws Exception\AssertionFailed
|
||||
*/
|
||||
static function logout()
|
||||
function logout()
|
||||
{
|
||||
$backend = self::backend();
|
||||
|
||||
return $backend instanceof Auth\BackendSSO ? $backend->logout() : null;
|
||||
return $this->backend instanceof Auth\BackendSSO ? $this->backend->logout() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,11 +172,9 @@ class Auth
|
||||
*
|
||||
* @return array of needed keys in session
|
||||
*/
|
||||
static function needSession()
|
||||
function needSession()
|
||||
{
|
||||
$backend = self::backend();
|
||||
|
||||
return method_exists($backend, 'needSession') ? $backend->needSession() : [];
|
||||
return method_exists($this->backend, 'needSession') ? $this->backend->needSession() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API - Authentication via SAML or everything supported by SimpleSAMLphp
|
||||
* EGroupware API - Authentication via SAML, Shibboleth or everything supported by SimpleSAMLphp
|
||||
*
|
||||
* @link https://www.egroupware.org
|
||||
* @link https://simplesamlphp.org/docs/stable/
|
||||
@ -16,59 +16,46 @@ use SimpleSAML;
|
||||
use EGroupware\Api\Exception;
|
||||
|
||||
/**
|
||||
* Authentication based on SAML or everything supported by SimpleSAMLphp
|
||||
* Authentication based on SAML, Shibboleth or everything supported by SimpleSAMLphp
|
||||
*
|
||||
* SimpleSAMLphp is installed together with EGroupware and a default configuration is created in EGroupware
|
||||
* files subdirectory "saml", once "Saml" is set as authentication method in setup and eg. the login page is loaded.
|
||||
* files subdirectory "saml" eg. when you first store it's configuration in Setup > Configuration > SAML/Shibboleth
|
||||
*
|
||||
* It will NOT work, before you configure at least one IdP (Identity Provider) for the default-sp (Service Provider) in saml/authsourcres.php:
|
||||
* Storing setup configuration modifies the following files:
|
||||
* a) $files_dir/saml/config.php
|
||||
* b) $files_dir/saml/authsources.php (only "default-sp" is used currently)
|
||||
* c) $files_dir/saml/metadata/*
|
||||
* d) $files_dir/saml/cert/*
|
||||
* Modification is only on certain values, everything else can be edited to suit your needs.
|
||||
*
|
||||
* // An authentication source which can authenticate against both SAML 2.0
|
||||
* // and Shibboleth 1.3 IdPs.
|
||||
* 'default-sp' => [
|
||||
* 'saml:SP',
|
||||
* Initially also a key-pair is generated as $files_dir/saml/cert/saml.{pem,crt}.
|
||||
* If you want or have to use a different certificate, best replace these with your files (they are referenced multiple times!).
|
||||
* They must stay in the files directory and can NOT be symlinks to eg. /etc, as only files dir is mounted into the container!
|
||||
*
|
||||
* // The entity ID of this SP.
|
||||
* // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL.
|
||||
* 'entityID' => null,
|
||||
* Authentication / configuration can be tested independent of EGroupware by using https://example.org/egroupware/saml/
|
||||
* with the "admin" user and password stored in cleartext in $files_dir/saml/config.php under 'auth.adminpassword'.
|
||||
*
|
||||
* // The entity ID of the IdP this SP should contact.
|
||||
* // Can be NULL/unset, in which case the user will be shown a list of available IdPs.
|
||||
* 'idp' => 'https://samltest.id/saml/idp',
|
||||
*
|
||||
* And the IdP's metadata in saml/metadata/saml20-idp-remote.php
|
||||
*
|
||||
* $metadata['https://samltest.id/saml/idp'] = [
|
||||
* 'SingleSignOnService' => 'https://samltest.id/idp/profile/SAML2/Redirect/SSO',
|
||||
* 'SingleLogoutService' => 'https://samltest.id/idp/profile/Logout',
|
||||
* 'certificate' => 'samltest.id.pem',
|
||||
* ];
|
||||
*
|
||||
* https://samltest.id/ is just a SAML / Shibboleth test side allowing AFTER uploading your metadata to test with a couple of static test-accounts.
|
||||
*
|
||||
* The metadata can be downloaded by via https://example.org/egroupware/saml/ under Federation, it also allows to test the authentication.
|
||||
* The required (random) Admin password can be found in /var/lib/egrouwpare/default/saml/config.php searching for auth.adminpassword.
|
||||
*
|
||||
* Alternativly you can also modify the following metadata example by replacing https://example.org/ with your domain:
|
||||
*
|
||||
* <?xml version="1.0"?>
|
||||
* <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://example.org/egroupware/saml/module.php/saml/sp/metadata.php/default-sp">
|
||||
* <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol">
|
||||
* <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://example.org/egroupware/saml/module.php/saml/sp/saml2-logout.php/default-sp"/>
|
||||
* <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://example.org/egroupware/saml/module.php/saml/sp/saml2-acs.php/default-sp" index="0"/>
|
||||
* <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:1.0:profiles:browser-post" Location="https://example.org/egroupware/saml/module.php/saml/sp/saml1-acs.php/default-sp" index="1"/>
|
||||
* <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="https://example.org/egroupware/saml/module.php/saml/sp/saml2-acs.php/default-sp" index="2"/>
|
||||
* <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" Location="https://example.org/egroupware/saml/module.php/saml/sp/saml1-acs.php/default-sp/artifact" index="3"/>
|
||||
* </md:SPSSODescriptor>
|
||||
* <md:ContactPerson contactType="technical">
|
||||
* <md:GivenName>Admin</md:GivenName>
|
||||
* <md:SurName>Name</md:SurName>
|
||||
* <md:EmailAddress>mailto:admin@example.org</md:EmailAddress>
|
||||
* </md:ContactPerson>
|
||||
* </md:EntityDescriptor>
|
||||
* There are basically three possible scenarios currently supported:
|
||||
* a) a single IdP and SAML configured as authentication method
|
||||
* --> gives full SSO (login page is never displayed, it directly redirects to the IdP)
|
||||
* b) one or multiple IdP, a discovery label and an other authentication type eg. SQL configured
|
||||
* --> uses the login page for local accounts plus a button or selectbox (depending on number of IdPs) to start SAML login
|
||||
* c) multiple IdP and SAML configured as authentication method
|
||||
* --> SimpleSAML discovery/selection page with a checkbox to remember the selection (SSO after first selection)
|
||||
*/
|
||||
class Saml implements BackendSSO
|
||||
{
|
||||
/**
|
||||
* Which entry in authsources.php to use.
|
||||
*
|
||||
* Setup > configuration always modifies "default-sp"
|
||||
*
|
||||
* A different SP can be configured via header.inc.php by adding at the end:
|
||||
*
|
||||
* EGroupware\Api\Auth\Saml::$auth_source = "other-sp";
|
||||
*/
|
||||
static public $auth_source = 'default-sp';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@ -79,7 +66,7 @@ class Saml implements BackendSSO
|
||||
}
|
||||
|
||||
/**
|
||||
* authentication against SAML
|
||||
* Authentication against SAML
|
||||
*
|
||||
* @param string $username username of account to authenticate
|
||||
* @param string $passwd corresponding password
|
||||
@ -89,7 +76,7 @@ class Saml implements BackendSSO
|
||||
function authenticate($username, $passwd, $passwd_type='text')
|
||||
{
|
||||
// login (redirects to IdP)
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as = new SimpleSAML\Auth\Simple(self::$auth_source);
|
||||
$as->requireAuth();
|
||||
|
||||
return true;
|
||||
@ -125,12 +112,13 @@ class Saml implements BackendSSO
|
||||
function login()
|
||||
{
|
||||
// login (redirects to IdP)
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->requireAuth();
|
||||
$as = new SimpleSAML\Auth\Simple(self::$auth_source);
|
||||
$as->requireAuth(preg_match('|^https://|', $_REQUEST['auth=saml']) ?
|
||||
['saml:idp' => $_REQUEST['auth=saml']] : []);
|
||||
|
||||
// cleanup session for EGroupware
|
||||
/* cleanup session for EGroupware: currently NOT used as we share the session with SimpleSAMLphp
|
||||
$session = SimpleSAML\Session::getSessionFromRequest();
|
||||
$session->cleanup();
|
||||
$session->cleanup();*/
|
||||
|
||||
// get attributes for (automatic) account creation
|
||||
$attrs = $as->getAttributes();
|
||||
@ -159,8 +147,8 @@ class Saml implements BackendSSO
|
||||
*/
|
||||
function logout()
|
||||
{
|
||||
$as = new SimpleSAML\Auth\Simple('default-sp');
|
||||
$as->logout();
|
||||
$as = new SimpleSAML\Auth\Simple(self::$auth_source);
|
||||
if ($as->isAuthenticated()) $as->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,7 +161,48 @@ class Saml implements BackendSSO
|
||||
*/
|
||||
function needSession()
|
||||
{
|
||||
return ['SimpleSAMLphp_SESSION'];
|
||||
return ['SimpleSAMLphp_SESSION', Api\Session::EGW_APPSESSION_VAR]; // Auth stores backend via Cache::setSession()
|
||||
}
|
||||
|
||||
const IDP_DISPLAY_NAME = 'OrganizationDisplayName';
|
||||
|
||||
/**
|
||||
* Display a IdP selection / discovery
|
||||
*
|
||||
* Will be displayed if IdP(s) are added in setup and a discovery label is specified.
|
||||
*
|
||||
* @return string|null html to display in login page or null to disable the selection
|
||||
*/
|
||||
static public function discovery()
|
||||
{
|
||||
if (empty($GLOBALS['egw_info']['server']['saml_discovery']) ||
|
||||
!($metadata = self::metadata()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
//error_log(__METHOD__."() metadata=".json_encode($metadata));
|
||||
$lang = Api\Translation::$userlang;
|
||||
$select = ['' => $GLOBALS['egw_info']['server']['saml_discovery']];
|
||||
foreach($metadata as $idp => $data)
|
||||
{
|
||||
$select[$idp] = $data[self::IDP_DISPLAY_NAME][$lang] ?: $data[self::IDP_DISPLAY_NAME]['en'];
|
||||
}
|
||||
return count($metadata) > 1 ?
|
||||
Api\Html::select('auth=saml', '', $select, true, 'class="onChangeSubmit"') :
|
||||
Api\Html::input('auth=saml', $GLOBALS['egw_info']['server']['saml_discovery'], 'submit', 'formmethod="get"');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array IdP => metadata pairs
|
||||
*/
|
||||
static public function metadata($files_dir=null)
|
||||
{
|
||||
$metadata = [];
|
||||
if (file_exists($file = ($files_dir ?: $GLOBALS['egw_info']['server']['files_dir']).'/saml/metadata/saml20-idp-remote.php'))
|
||||
{
|
||||
include $file;
|
||||
}
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
const ASYNC_JOB_ID = 'saml_metadata_refresh';
|
||||
@ -190,11 +219,7 @@ class Saml implements BackendSSO
|
||||
{
|
||||
$config =& $location['newsettings'];
|
||||
|
||||
/*error_log(__METHOD__."() ".json_encode(array_filter($config, function($value, $key) {
|
||||
return substr($key, 0, 5) === 'saml_' || $key === 'auth_type';
|
||||
}, ARRAY_FILTER_USE_BOTH), JSON_UNESCAPED_SLASHES));*/
|
||||
|
||||
if (empty($config['saml_idp'])) return; // nothing to do, if not idp defined
|
||||
if (empty($config['saml_idp'])) return; // nothing to do, if no idp defined
|
||||
|
||||
if (file_exists($config['files_dir'].'/saml/config.php'))
|
||||
{
|
||||
@ -204,7 +229,6 @@ class Saml implements BackendSSO
|
||||
|
||||
// install or remove async job to refresh metadata
|
||||
static $freq2times = [
|
||||
'hourly' => ['min' => 4], // hourly at minute 4
|
||||
'daily' => ['min' => 4, 'hour' => 4], // daily at 4:04am
|
||||
'weekly' => ['min' => 4, 'hour' => 4, 'dow' => 5], // Saturdays as 4:04am
|
||||
];
|
||||
@ -219,12 +243,37 @@ class Saml implements BackendSSO
|
||||
$async->cancel_timer(self::ASYNC_JOB_ID);
|
||||
}
|
||||
|
||||
// only refresh metadata if we have to, or request by user
|
||||
if ($config['saml_metadata_refresh'] !== 'no')
|
||||
{
|
||||
self::refreshMetadata($config);
|
||||
$metadata = self::metadata($config['files_dir']);
|
||||
$idps = self::splitIdP($config['saml_idp']);
|
||||
foreach($idps as $idp)
|
||||
{
|
||||
if (!isset($metadata[$idp]))
|
||||
{
|
||||
$metadata = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count($metadata) !== count($idps) || $config['saml_metadata_refresh'] === 'now')
|
||||
{
|
||||
self::refreshMetadata($config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Split multiple IdP
|
||||
*
|
||||
* @param string $config
|
||||
* @return string[]
|
||||
*/
|
||||
private static function splitIdP($config)
|
||||
{
|
||||
return preg_split('/[\n\r ]+/', trim($config)) ?: [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh metadata
|
||||
*
|
||||
@ -241,7 +290,8 @@ class Saml implements BackendSSO
|
||||
|
||||
$source = [
|
||||
'src' => $config['saml_metadata'],
|
||||
'whitelist' => [$config['saml_idp']], // only ready our idp, the whole thing can be huge
|
||||
// only read/configure our idp(s), the whole thing can be huge
|
||||
'whitelist' => self::splitIdP($config['saml_idp']),
|
||||
];
|
||||
if (!empty($config['saml_certificate']))
|
||||
{
|
||||
@ -271,7 +321,15 @@ class Saml implements BackendSSO
|
||||
$GLOBALS['egw_info']['server']['usecookies'] = true;
|
||||
$config['baseurlpath'] = Api\Framework::getUrl(Api\Egw::link('/saml/'));
|
||||
$config['username_oid'] = [self::usernameOid($config)];
|
||||
|
||||
// if multiple IdP's are configured, do NOT specify one to let user select
|
||||
if (count(self::splitIdP($config['saml_idp'])) > 1)
|
||||
{
|
||||
unset($config['saml_idp']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$config['saml_idp'] = trim($config['saml_idp']);
|
||||
}
|
||||
// update config.php and default-sp in authsources.php
|
||||
foreach([
|
||||
'authsources.php' => [
|
||||
@ -445,12 +503,18 @@ class Saml implements BackendSSO
|
||||
|
||||
case 'authsources.php':
|
||||
$replacements = [
|
||||
"'idp' => null," => "'idp' => ".self::quote($config['saml_idp']).',',
|
||||
"'idp' => null," => "'idp' => ".self::quote(
|
||||
count(self::splitIdP($config['saml_idp'])) <= 1 ? trim($config['saml_idp']) : null).',',
|
||||
"'discoURL' => null," => "'discoURL' => null,\n\n".
|
||||
// add our private and public keys
|
||||
"\t'privatekey' => 'saml.pem',\n\n".
|
||||
"\t// to include certificate in metadata\n".
|
||||
"\t'certificate' => 'saml.crt',\n\n".
|
||||
"\t// new certificates for rotation: add new, wait for IdP sync, swap old and new, wait, comment again\n".
|
||||
"\t//'new_privatekey' => 'new-saml.pem',\n".
|
||||
"\t//'new_certificate' => 'new-saml.crt',\n\n".
|
||||
"\t// logout is NOT signed by default, but signature is required from the uni-kl.de IdP for logout\n".
|
||||
"\t'sign.logout' => true,\n\n".
|
||||
"\t'name' => [\n".
|
||||
"\t\t'en' => ".self::quote($config['saml_sp'] ?: 'EGroupware').",\n".
|
||||
"\t],\n\n".
|
||||
|
@ -402,7 +402,7 @@ class Cache
|
||||
*/
|
||||
static public function &getSession($app,$location,$callback=null,array $callback_params=array(),$expiration=0)
|
||||
{
|
||||
if (isset($_SESSION[Session::EGW_SESSION_ENCRYPTED]))
|
||||
if (!isset($_SESSION) || isset($_SESSION[Session::EGW_SESSION_ENCRYPTED]))
|
||||
{
|
||||
if (Session::ERROR_LOG_DEBUG) error_log(__METHOD__.' called after session was encrypted --> ignored!');
|
||||
return null; // can no longer store something in the session, eg. because commit_session() was called
|
||||
|
@ -585,7 +585,7 @@ class Db
|
||||
{
|
||||
foreach(get_included_files() as $file)
|
||||
{
|
||||
if (strpos($file,'adodb') !== false && !in_array($file,(array)$_SESSION['egw_required_files']))
|
||||
if (strpos($file,'adodb') !== false && !in_array($file,(array)$_SESSION['egw_required_files']) && isset($_SESSION))
|
||||
{
|
||||
$_SESSION['egw_required_files'][] = $file;
|
||||
//error_log(__METHOD__."() egw_required_files[] = $file");
|
||||
|
@ -81,6 +81,23 @@ class Login
|
||||
$tmpl->set_var('2fa_class', 'et2_required');
|
||||
}
|
||||
}
|
||||
|
||||
// check if we need some discovery (select login options eg. a SAML IdP), hide it if not
|
||||
$discovery = '';
|
||||
foreach(Api\Hooks::process('login_discovery', [], true) as $app => $data)
|
||||
{
|
||||
if (!empty($data)) $discovery .= $data;
|
||||
}
|
||||
if (!empty($discovery))
|
||||
{
|
||||
$tmpl->set_var('discovery', $discovery);
|
||||
}
|
||||
else
|
||||
{
|
||||
$tmpl->set_block('login_form','discovery_block');
|
||||
$tmpl->set_var('discovery_block', '');
|
||||
}
|
||||
|
||||
// hide change-password fields, if not requested
|
||||
if (!$change_passwd)
|
||||
{
|
||||
|
@ -1444,9 +1444,11 @@ class Session
|
||||
if (!$GLOBALS['egw_info']['user']['sessionid'] || $sessionid == $GLOBALS['egw_info']['user']['sessionid'])
|
||||
{
|
||||
// eg. SAML logout will fail, if there is no more session --> remove everything else
|
||||
if (($needed = Auth::needSession()) && array_intersect($needed, array_keys($_SESSION)))
|
||||
$auth = new Auth();
|
||||
if (($needed = $auth->needSession()) && array_intersect($needed, array_keys($_SESSION)))
|
||||
{
|
||||
$_SESSION = array_intersect_key($_SESSION['SimpleSAMLphp_SESSION'], array_flip($needed));
|
||||
$_SESSION = array_intersect_key($_SESSION, array_flip($needed));
|
||||
Auth::backend($auth->backendType()); // backend is stored in session
|
||||
return true;
|
||||
}
|
||||
if (self::ERROR_LOG_DEBUG) error_log(__METHOD__." ********* about to call session_destroy!");
|
||||
|
@ -39,6 +39,8 @@ elseif(strpos($redirectTarget, '[?&]cd=') !== false)
|
||||
|
||||
if ($verified)
|
||||
{
|
||||
$auth = new Api\Auth();
|
||||
|
||||
// remove remember me cookie on explicit logout, unless it is a second factor
|
||||
if ($GLOBALS['egw']->session->removeRememberMeTokenOnLogout())
|
||||
{
|
||||
@ -53,7 +55,7 @@ Api\Session::egw_setcookie('kp3');
|
||||
Api\Session::egw_setcookie('domain');
|
||||
|
||||
// SSO Logout (does not return for SSO systems)
|
||||
Api\Auth::logout();
|
||||
if (isset($auth)) $auth->logout();
|
||||
|
||||
// $GLOBALS['egw']->redirect($redirectTarget);
|
||||
?>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -265,7 +265,7 @@ div#loginMainDiv.stockLoginBackground {
|
||||
margin-top: 7px;
|
||||
width: auto;
|
||||
}
|
||||
input[type="submit"] {
|
||||
input[type="submit"], select.onChangeSubmit {
|
||||
background-color: #0a5ca5;
|
||||
.color_0_gray;
|
||||
.fontsize_xxl;
|
||||
@ -275,6 +275,9 @@ div#loginMainDiv.stockLoginBackground {
|
||||
&:focus {}
|
||||
margin-top: 25px;
|
||||
}
|
||||
select.onChangeSubmit {
|
||||
padding-left: 25px;
|
||||
}
|
||||
.registration {
|
||||
font-size: 11px;
|
||||
a:not(:first-child) {
|
||||
|
@ -28,6 +28,13 @@
|
||||
<input type="hidden" name="account_type" value="u" />
|
||||
</td>
|
||||
</tr>
|
||||
<!-- BEGIN discovery_block -->
|
||||
<tr>
|
||||
<td>
|
||||
{discovery}
|
||||
</td>
|
||||
</tr>
|
||||
<!-- END discovery_block -->
|
||||
<tr>
|
||||
<td>
|
||||
<span class="field_icons username"></span>
|
||||
|
@ -75,6 +75,13 @@
|
||||
</td>
|
||||
</tr>
|
||||
<!-- END domain_selection -->
|
||||
<!-- BEGIN discovery_block -->
|
||||
<tr>
|
||||
<td>
|
||||
{discovery}
|
||||
</td>
|
||||
</tr>
|
||||
<!-- END discovery_block -->
|
||||
<!-- BEGIN change_password -->
|
||||
<tr>
|
||||
<td>
|
||||
|
@ -9,21 +9,26 @@
|
||||
* @subpackage authentication
|
||||
*/
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
// we have to set session-cookie name used by EGroupware!
|
||||
ini_set('session.name', 'sessionid');
|
||||
|
||||
require_once __DIR__.'/../api/src/autoload.php';
|
||||
|
||||
$GLOBALS['egw_info'] = [
|
||||
'flags' => [
|
||||
//'currentapp' => 'login', // db connection, no auth
|
||||
'noapi' => true, // no db connection, but autoloader, files_dir MUST be set correct!
|
||||
],
|
||||
'server' => [
|
||||
'files_dir' => '/var/lib/egroupware/default/files',
|
||||
'temp_dir' => '/tmp',
|
||||
// default files and temp directories for name based instances (eg. our hosting) or container installation
|
||||
'files_dir' => file_exists('/var/lib/egroupware/'.Api\Header\Http::host().'/files') ?
|
||||
'/var/lib/egroupware/'.Api\Header\Http::host().'/files' : '/var/lib/egroupware/default/files',
|
||||
'temp_dir' => file_exists('/var/lib/egroupware/'.Api\Header\Http::host().'/tmp') ?
|
||||
'/var/lib/egroupware/'.Api\Header\Http::host().'/tmp' : '/tmp',
|
||||
],
|
||||
];
|
||||
require_once __DIR__.'/../header.inc.php';
|
||||
|
||||
use EGroupware\Api;
|
||||
|
||||
Api\Auth\Saml::checkDefaultConfig();
|
@ -478,9 +478,14 @@
|
||||
<td colspan="2"><b>{lang_If_using_SAML_2.0 / Shibboleth / SimpleSAMLphp}:</b></td>
|
||||
</tr>
|
||||
|
||||
<tr class="row_off">
|
||||
<td>{lang_Label_to_display_as_option_on_login_page}:<br/>{lang_or_leave_empty_and_select_SAML_as_authentication_type_above_for_single_sign_on}</td>
|
||||
<td><input name="newsettings[saml_discovery]" placeholder="{lang_University_Login}" value="{value_saml_discovery}" size="20" /></td>
|
||||
</tr>
|
||||
|
||||
<tr class="row_on">
|
||||
<td>{lang_Identity_Provider}:</td>
|
||||
<td><input name="newsettings[saml_idp]" placeholder="https://idp.rhrk.uni-kl.de/idp/shibboleth" value="{value_saml_idp}" size="64" /></td>
|
||||
<td>{lang_Identity_Provider}:<br/>{lang_You_can_specify_multiple_IdP_on_separate_lines.}</td>
|
||||
<td><textarea name="newsettings[saml_idp]" placeholder="https://idp.rhrk.uni-kl.de/idp/shibboleth" rows="3" cols="64">{value_saml_idp}</textarea></td>
|
||||
</tr>
|
||||
|
||||
<tr class="row_off">
|
||||
@ -490,7 +495,6 @@
|
||||
<select name="newsettings[saml_metadata_refresh]">
|
||||
<option value="daily"{selected_saml_metadata_refresh_daily}>{lang_daily}</option>
|
||||
<option value="weekly"{selected_saml_metadata_refresh_weekly}>{lang_weekly}</option>
|
||||
<option value="hourly"{selected_saml_metadata_refresh_hourly}>{lang_hourly}</option>
|
||||
<option value="no"{selected_saml_metadata_refresh_no}>{lang_not_automatic}</option>
|
||||
<option value="now"{selected_saml_metadata_refresh_now}>{lang_just_now}</option>
|
||||
</select>
|
||||
@ -536,7 +540,11 @@
|
||||
</tr>
|
||||
|
||||
<tr class="row_off">
|
||||
<td colspan="2">{lang_The_used_SimpleSAMLphp_allows_a_lot_more_configuration_/_different_authentication_types_via_its_config_files in} {value_files_dir}/saml</td>
|
||||
<td colspan="2">
|
||||
{lang_The_used_SimpleSAMLphp_allows_a_lot_more_configuration_/_different_authentication_types_via_its_config_files in} {value_files_dir}/saml<br/>
|
||||
{lang_More_information}: <a target="_blank" href="https://github.com/EGroupware/egroupware/blob/master/api/src/Auth/Saml.php#L19">
|
||||
https://github.com/EGroupware/egroupware/blob/master/api/src/Auth/Saml.php</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="row_off">
|
||||
|
Loading…
Reference in New Issue
Block a user