Commit fb552e79 authored by Robert Lyon's avatar Robert Lyon Committed by Cecilia Vela Gurovic
Browse files

Bug 1716820: Display the IdPs in saml config page



And allow deleting of unused ones

behatnotneeded

Change-Id: I1e00cb207b8d5b29711a1301f7a25fed772b8e67
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 5c8d1fe9
<?php
/**
*
* @package mahara
* @subpackage core
* @author Catalyst IT Ltd
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL version 3 or later
* @copyright For copyright information on Mahara, please see the README file distributed with this software.
*
*/
define('INTERNAL', 1);
define('JSON', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
safe_require('auth', 'saml');
$idp = param_variable('idp', null);
$data = new StdClass();
$data->error = false;
if (file_exists(AuthSaml::prepare_metadata_path($idp))) {
// Double check that the idp is not being used
if (get_field('auth_instance_config', 'instance', 'field', 'institutionidpentityid', 'value', $idp)) {
$data->error = 'metadata in use - unable to delete';
}
else {
// Ok to delete
if (!unlink(AuthSaml::prepare_metadata_path($idp))) {
$data->error = 'unable to delete metadata';
}
else {
$data->success = true;
}
}
}
else {
$data->error = 'unable to find metadata';
}
json_reply(false, array('data' => $data));
......@@ -305,73 +305,10 @@ function auth_saml_find_authinstance($saml_attributes) {
*/
function auth_saml_disco_screen($list, $preferred) {
$idps = array();
$lang = current_language();
$lang = explode('.', $lang);
$lang = strtolower(array_shift($lang));
$haslogos = false;
foreach ($list as $entityid => $value) {
$desc = $name = $entityid;
if (isset($value['description'][$lang])) {
$desc = $value['description'][$lang];
}
if (isset($value['name'][$lang])) {
$name = $value['name'][$lang];
}
$idplogo = array();
if (isset($value['UIInfo']) && isset($value['UIInfo']['Logo'])) {
$haslogos = true;
// Fetch logo from provider if given
$logos = $value['UIInfo']['Logo'];
foreach ($logos as $logo) {
if (isset($logo['lang']) && $logo['lang'] == $lang) {
$idplogo = $logo;
break;
}
}
// None matching the lang wanted so use the first one
if (empty($idplogo)) {
$idplogo = $logos[0];
}
}
$idps[]= array('idpentityid' => $entityid, 'name' => $name, 'description' => $desc, 'logo' => $idplogo);
}
usort($idps, function($a, $b) {
return $a['name'] > $b['name'];
});
$idps = array(
'count' => count($idps),
'limit' => count($idps),
'offset' => 1,
'data' => $idps,
);
$cols = array(
'logo' => array('name' => get_string('logo', 'auth.saml'),
'template' => 'auth:saml:idplogo.tpl',
'class' => 'short',
'sort' => 'false'),
'idpentityid' => array('name' => get_string('idpentityid', 'auth.saml'),
'template' => 'auth:saml:idpentityid.tpl',
'class' => 'col-sm-3',
'sort' => false),
'description' => array('name' => get_string('idpprovider','auth.saml'),
'sort' => false),
);
if ($haslogos === false) {
unset($cols['logo']);
}
$smarty = smarty_core();
$smarty->assign('results', $idps);
$smarty->assign('cols', $cols);
$smarty->assign('pagedescriptionhtml', get_string('selectidp', 'auth.saml'));
$idps = $smarty->fetch('auth:saml:idptable.tpl');
list ($cols, $html) = PluginAuthSaml::idptable($list, $preferred);
$smarty = smarty(array(), array(), array(), array('pagehelp' => false, 'sidebars' => false));
$smarty->assign('columns', $cols);
$smarty->assign('idps', $idps);
$smarty->assign('idps', $html);
$smarty->assign('preferred', $preferred);
$smarty->assign('PAGEHEADING', get_string('disco', 'auth.saml'));
$smarty->display('auth:saml:disco.tpl');
......
......@@ -21,6 +21,7 @@ $string['manage_certificate2'] = 'This is the certificate generated as part of t
$string['nullprivatecert'] = "Could not generate or save the private key";
$string['nullpubliccert'] = "Could not generate or save the public certificate";
$string['defaultinstitution'] = 'Default institution';
$string['deleteidp'] = 'Delete IdP';
$string['description'] = 'Authenticate against a SAML 2.0 Identity Provider service';
$string['disco'] = 'Identity Provider discovery';
$string['errorbadinstitution'] = 'Institution for connecting user not resolved';
......@@ -56,9 +57,11 @@ $string['idpentityupdatedduplicates'] = array(
);
$string['metarefresh_metadata_url'] = 'Metadata URL for auto-refresh';
$string['idpprovider'] = 'Provider';
$string['idptable'] = 'Installed Identity Providers';
$string['institutionattribute'] = 'Institution attribute (contains "%s")';
$string['institutionidp'] = 'Institution Identity Provider SAML metadata';
$string['institutionidpentity'] = 'Available Identity Providers';
$string['institutions'] = 'Institutions';
$string['institutionvalue'] = 'Institution value to check against attribute';
$string['libchecks'] = 'Checking for correct libraries installed: %s';
$string['link'] = 'Link accounts';
......
......@@ -630,6 +630,36 @@ class PluginAuthSaml extends PluginAuth {
)), $elements);
}
// Show the current metadata installed on the site so we can delete them
// We need to handle this outside the current pieform as we don't want to submit that and re-create a new certificate
$disco = self::get_raw_disco_list();
if (count($disco['list']) > 0) {
$discoused = array();
if ($discousedtmp = get_records_sql_array("SELECT i.name, i.displayname, aic.value,
CASE WHEN i.name = 'mahara' THEN 1 ELSE 0 END AS site
FROM {auth_instance} ai
JOIN {auth_instance_config} aic ON aic.instance = ai.id
JOIN {institution} i ON i.name = ai.institution
WHERE ai.authname = ? and field = ?", array('saml', 'institutionidpentityid'))) {
// turn $discoused into useful array structure
foreach ($discousedtmp as $used) {
$discoused[$used->value][] = $used;
}
}
list($cols, $html) = self::idptable($disco['list'], null, $discoused, true);
$smarty = smarty_core();
$smarty->assign('html', $html);
$smarty->assign('cols', $cols);
$out = $smarty->fetch('auth:saml:idptableconfig.tpl');
$elements = array_merge($elements , array(
'idptable' => array(
'type' => 'html',
'value' => $out,
)
));
}
return array(
'elements' => $elements,
);
......@@ -654,6 +684,107 @@ class PluginAuthSaml extends PluginAuth {
}
public static function idptable($list, $preferred = array(), $institutions = array(), $showdelete = false) {
$idps = array();
$lang = current_language();
$lang = explode('.', $lang);
$lang = strtolower(array_shift($lang));
$haslogos = $hasinstitutions = $hasdelete = false;
foreach ($list as $entityid => $value) {
$candelete = false;
$desc = $name = $entityid;
if (isset($value['description'][$lang])) {
$desc = $value['description'][$lang];
}
if (isset($value['name'][$lang])) {
$name = $value['name'][$lang];
}
$idplogo = array();
if (isset($value['UIInfo']) && isset($value['UIInfo']['Logo'])) {
$haslogos = true;
// Fetch logo from provider if given
$logos = $value['UIInfo']['Logo'];
foreach ($logos as $logo) {
if (isset($logo['lang']) && $logo['lang'] == $lang) {
$idplogo = $logo;
break;
}
}
// None matching the lang wanted so use the first one
if (empty($idplogo)) {
$idplogo = $logos[0];
}
}
$insts = array();
if (!empty($institutions) && !empty($institutions[$entityid])) {
$hasinstitutions = true;
$insts = $institutions[$entityid];
}
else if ($showdelete) {
$hasdelete = true;
$candelete = true;
}
$idps[]= array('idpentityid' => $entityid, 'name' => $name, 'description' => $desc, 'logo' => $idplogo, 'institutions' => $insts, 'delete' => $candelete);
}
usort($idps, function($a, $b) {
return $a['name'] > $b['name'];
});
$idps = array(
'count' => count($idps),
'limit' => count($idps),
'offset' => 1,
'data' => $idps,
);
$cols = array(
'logo' => array(
'name' => get_string('logo', 'auth.saml'),
'template' => 'auth:saml:idplogo.tpl',
'class' => 'short',
'sort' => false
),
'idpentityid' => array(
'name' => get_string('idpentityid', 'auth.saml'),
'template' => 'auth:saml:idpentityid.tpl',
'class' => 'col-sm-3',
'sort' => false
),
'description' => array(
'name' => get_string('idpprovider','auth.saml'),
'sort' => false
),
'institutions' => array(
'name' => get_string('institutions', 'auth.saml'),
'template' => 'auth:saml:idpinstitutions.tpl',
'sort' => false
),
'delete' => array(
'name' => get_string('deleteidp', 'auth.saml'),
'template' => 'auth:saml:idpdelete.tpl',
'sort' => false
),
);
if ($haslogos === false) {
unset($cols['logo']);
}
if ($hasinstitutions === false) {
unset($cols['institutions']);
}
if ($hasdelete === false) {
unset($cols['delete']);
}
$smarty = smarty_core();
$smarty->assign('results', $idps);
$smarty->assign('cols', $cols);
$smarty->assign('pagedescriptionhtml', get_string('selectidp', 'auth.saml'));
$html = $smarty->fetch('auth:saml:idptable.tpl');
return array($cols, $html);
}
public static function has_instance_config() {
return true;
}
......@@ -792,13 +923,18 @@ class PluginAuthSaml extends PluginAuth {
return array($entityid, $idps);
}
public static function get_raw_disco_list() {
PluginAuthSaml::init_simplesamlphp();
$discoHandler = new PluginAuthSaml_IdPDisco(array('saml20-idp-remote', 'shib13-idp-remote'), 'saml');
return $discoHandler->getTheIdPs();
}
public static function get_disco_list($lang = null, $entityidps = array()) {
if (empty($lang)) {
$lang = current_language();
}
PluginAuthSaml::init_simplesamlphp();
$discoHandler = new PluginAuthSaml_IdPDisco(array('saml20-idp-remote', 'shib13-idp-remote'), 'saml');
$disco = $discoHandler->getTheIdPs();
$disco = self::get_raw_disco_list();
if (count($disco['list']) > 0) {
$lang = explode('.', $lang);
$lang = strtolower(array_shift($lang));
......
{if $r.delete}
<button type="button" onclick="deleteidp(this, '{$r.idpentityid}')" name="delete" value="{$r.idpentityid}" class="btn-link btn btn-xs pull-right" alt='{str tag=deletespecific section=mahara arg1=$r.name}'>
<span class="icon icon-trash text-danger icon-lg" role="presentation" aria-hidden="true"></span>
<span class="sr-only">
{str tag=delete section=mahara}
</span>
</button>
{/if}
{if $r.institutions}
{foreach from=$r.institutions item=institution name=ags}
{if !$institution->site}<a href="{$WWWROOT}institution/index.php?institution={$institution->name}">{/if}
{$institution->displayname}
{if !$institution->site}</a>{/if}
{if !$dwoo.foreach.ags.last}, {/if}
{/foreach}
{/if}
\ No newline at end of file
<h3 class="title">{str tag='idptable' section='auth.saml'}</h3>
<table id="idplist" class="table table-striped listing">
<thead>
<tr>
{foreach from=$cols item=col}
<th>{$col['name']}</th>
{/foreach}
</tr>
</thead>
<tbody>
{$html|safe}
</tbody>
</table>
<script type="application/javascript">
function deleteidp(el, idp) {
var data = { 'idp' : idp };
var row = $(el).closest('tr');
sendjsonrequest(config.wwwroot + 'auth/saml/idpdelete.json.php', data, 'POST', function(data) {
if (data.data.error) {
alert(data.data.error);
}
else {
row.hide();
}
});
}
</script>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment