Commit 7850fad9 authored by Robert Lyon's avatar Robert Lyon

Bug 1855622: Create institution on SAML login if needed

Allowing a site admin not to have to set up all the institutions on
Mahara side manually

Change-Id: I3a240b4c0ad1d968489cdc4c083df6d851cd9abb
Signed-off-by: Robert Lyon's avatarRobert Lyon <robertl@catalyst.net.nz>
parent 612e261a
......@@ -271,10 +271,93 @@ function auth_saml_loginlink_submit(Pieform $form, $values) {
* @return object authinstance record
*/
function auth_saml_find_authinstance($saml_attributes) {
// find the one (it should be only one) that has the right field, and the right field value for institution
// find the one (it should be only one) that has the right field, and the right field value for institution
$instance = false;
$institutions = array();
if (get_config('saml_create_institution') && get_config('saml_create_institution_default')) {
// We can try and make the institution if it doesn't exist
// First check if there is another institution that we can get default saml metadata from
// This institution will be defined in the config
$configs = false;
foreach ($defaults = explode(',', get_config('saml_create_institution_default')) as $default) {
if (!record_exists('institution', 'name', $default)) {
// institution does not exist
continue;
}
$auths = get_column_sql("SELECT ai.id FROM {auth_instance_config} aic
JOIN {auth_instance} ai ON ai.id = aic.instance
WHERE ai.authname = ? AND ai.active = 1
AND aic.field = 'institutionidpentityid' AND aic.value IS NOT NULL
AND ai.institution = ?", array('saml', $default));
if ($auths) {
foreach ($auths as $auth) {
// Select 'field' first so it is used as the array key
if ($configs = get_records_sql_assoc("SELECT field, value, instance FROM {auth_instance_config}
WHERE instance = ?", array($auth))) {
if (isset($saml_attributes[$configs['institutionattribute']->value]) &&
isset($saml_attributes[$configs['user_attribute']->value])) {
// Institution default SAML found
break;
}
else {
$configs = false;
continue;
}
}
}
}
}
// now we have the default configs
if ($configs) {
foreach ($saml_attributes[$configs['institutionattribute']->value] as $index => $attr) {
// does this institution use a regex match against the institution check value?
if ($configvalue = $configs['institutionregex']->value) {
$is_regex = (boolean) $configvalue;
}
else {
$is_regex = false;
}
$instmatch = $is_regex ? "aic.value LIKE '%' || ? || '%'" : "aic.value = ?";
// If the institution exists and has active saml auth enabled
if ($inst = get_records_sql_array("SELECT ai.institution FROM {auth_instance} ai
JOIN {auth_instance_config} aic ON aic.instance = ai.id
WHERE aic.field = 'institutionvalue'
AND " . $instmatch . "
AND ai.authname = 'saml'
AND ai.active = 1", array($attr))) {
// All good so continue
log_debug('institution ' . $inst[0]->institution . ' is all ready');
continue;
}
else if ($inst = get_records_sql_array("SELECT ai.institution FROM {auth_instance} ai
JOIN {auth_instance_config} aic ON aic.instance = ai.id
WHERE aic.field = 'institutionvalue'
AND " . $instmatch . "
AND ai.authname = 'saml'", array($attr))) {
// Institution exists but SAML auth not active - so make it active
log_debug('institution ' . $inst[0]->institution . ' SAML auth is now active');
set_field('auth_instance', 'active', 1, 'institution', $inst[0]->institution, 'authname', 'saml');
}
// Because we can't find a SAML mapping of IdP institution to Mahara institution we will try and see if there is a Mahara institution with same name as IdP institution value
else if ($institution = get_record('institution', 'name', $attr)) {
// Institution exists but no SAML auth instance - so create one
add_institution_saml_auth($attr, $configs);
log_debug('institution ' . $attr . ' SAML auth is added');
}
else {
// Institution does not exist - create the institution and the SAML instance
$institution = institution_generate_name($attr);
$displayname = isset($configs['organisationname']) && !empty($saml_attributes[$configs['organisationname']->value][$index]) ? $saml_attributes[$configs['organisationname']->value][$index] : $attr;
$newinstitution = new Institution();
$newinstitution->initialise($institution, $displayname);
$newinstitution->commit();
add_institution_saml_auth($institution, $configs);
log_debug('institution ' . $attr . ' is now created and SAML auth is added');
}
}
}
}
// find all the possible institutions/auth instances of type saml
$instances = recordset_to_array(get_recordset_sql("SELECT * FROM {auth_instance_config} aic, {auth_instance} ai WHERE ai.id = aic.instance AND ai.authname = 'saml' AND ai.active = 1 AND aic.field = 'institutionattribute'"));
foreach ($instances as $row) {
......@@ -315,6 +398,25 @@ function auth_saml_find_authinstance($saml_attributes) {
return $instance;
}
function add_institution_saml_auth($institution, $configs=array()) {
$maxpriority = get_field_sql("SELECT MAX(priority) FROM {auth_instance} WHERE institution = ?", array($institution));
$priority = is_null($maxpriority) ? 0 : $maxpriority + 1;
$fordb = new stdClass();
$fordb->instancename = 'saml';
$fordb->priority = $priority;
$fordb->institution = $institution;
$fordb->authname = 'saml';
$fordb->active = 1;
$instanceid = insert_record('auth_instance', $fordb, 'id', true);
// Add in the configs for new institution saml auth
foreach ($configs as $k => $v) {
if ($k == 'institutionvalue') {
$v->value = $institution;
}
execute_sql("INSERT INTO {auth_instance_config} (instance, field, value) VALUES (?, ?, ?)", array($instanceid, $k, $v->value));
}
return $instanceid;
}
/**
* present the IdP discovery screen if there are more than one
......
......@@ -94,6 +94,7 @@ $string['samlfieldforrolesiteadmin'] = 'Role mapping for site administrator';
$string['samlfieldforrolesitestaff'] = 'Role mapping for site staff';
$string['samlfieldforroleinstadmin'] = 'Role mapping for institution administrator';
$string['samlfieldforroleinststaff'] = 'Role mapping for institution staff';
$string['samlfieldfororganisationname'] = 'SSO field for Organisation';
$string['samlfieldauthloginmsg'] = 'Wrong login message';
$string['spentityid'] = "Service Provider entityId";
$string['title'] = 'SAML';
......
......@@ -98,6 +98,7 @@ class AuthSaml extends Auth {
$this->config['rolesitestaff'] = '';
$this->config['roleinstadmin'] = '';
$this->config['roleinststaff'] = '';
$this->config['organisationname'] = '';
$this->instanceid = $id;
if (!empty($id)) {
......@@ -448,6 +449,7 @@ class PluginAuthSaml extends PluginAuth {
'rolesitestaff' => '',
'roleinstadmin' => '',
'roleinststaff' => '',
'organisationname' => '',
'emailfield' => '',
'studentidfield' => '',
'updateuserinfoonlogin' => 1,
......@@ -1364,6 +1366,12 @@ EOF;
'defaultvalue' => self::$default_config['studentidfield'],
'help' => true,
),
'organisationname' => array(
'type' => 'text',
'title' => get_string('samlfieldfororganisationname', 'auth.saml'),
'defaultvalue' => self::$default_config['organisationname'],
'help' => false,
),
'avatar' => array(
'type' => 'text',
'title' => get_string('samlfieldforavatar', 'auth.saml'),
......@@ -1574,6 +1582,7 @@ EOF;
'rolesitestaff' => $values['rolesitestaff'],
'roleinstadmin' => $values['roleinstadmin'],
'roleinststaff' => $values['roleinststaff'],
'organisationname' => $values['organisationname'],
'updateuserinfoonlogin' => $values['updateuserinfoonlogin'],
'institutionattribute' => $values['institutionattribute'],
'institutionvalue' => $values['institutionvalue'],
......
......@@ -831,3 +831,13 @@ $cfg->saml_log_attributes = false;
* To get passed this, by allowing just a unique identifier/username, we set the follwing flag
*/
// $cfg->saml_create_minimum_user=true;
/**
* Allow SAML to create an institution when creating a new user if the institution they need
* to belong to doesn't yet exist. The IdP can pass an institution display name through
* and be mapped via the SAML instance setting 'samlfieldfororganisationname'.
* To make a new institution you need to define what institution to fetch an existing SAML
* instance from to be used as the default 'template' SAML settings.
*/
//$cfg->saml_create_institution=true;
//$cfg->saml_create_institution_default = 'mahara';
Markdown is supported
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