Configuration is broken on Multisite
-
I’m trying to set up SAML 2.0 Single Sign-On on a WordPress Multisite installation.
Doing Network Activate doesn’t work – the plugin is activated, but tabs in the settings page show a “You do not have sufficient permissions to access this page.” error. Specifically:
Network Admin plugin settings:
* Error on General page
* Error on Service Provider pageSub-site Admin plugin settings:
* Error on Identity Provider page
Additionally, settings did not appear to be shared between sites – making settings changes as the Network Admin did not propagate to the sub-sites.
Deactivating SAML 2.0 Single Sign-On, installing and activating the Multisite Plugin Manager plugin, and then using the MPM plugin to universally activate SAML 2.0 Single Sign-On fixed the latter problem. However, it didn’t fix the Permissions error.
https://www.ads-software.com/plugins/saml-20-single-sign-on/
-
After digging into the code, it appears that the above behavior is correct for a Multisite, but there’s still a bug – the tabs that should be hidden in each view (Network Admin vs sub-site Admin) are not!
There is a simple fix to this.
First, edit nav_tabs.php to only show the appropriate tabs at the right admin level.
Second, add documentation for Multisite usage; it’s not immediately apparent how to get it working.
This is what I replaced the code in nav_tabs.php with:
<?php $tab = $_GET['page']; $is_multisite = is_multisite(); $is_network_admin_page = is_network_admin(); if ($is_network_admin_page && $is_multisite) { $show_general = false; $show_sp = false; $show_idp = true; } elseif (!$is_network_admin_page && $is_multisite) { $show_general = true; $show_sp = true; $show_idp = false; } else { $show_general = true; $show_sp = true; $show_idp = true; } ?> <link rel="stylesheet" href="<?php echo constant('SAMLAUTH_URL') . '/lib/css/sso.css';?>" /> <link href="//netdna.bootstrapcdn.com/font-awesome/3.1.1/css/font-awesome.css" rel="stylesheet"> <div class="wrap"> <h2 class="nav-tab-wrapper"> Single Sign-On <?php if ($show_general) { ?><a href="?page=sso_general.php" class="nav-tab<?php if($tab == 'sso_general.php'){echo ' nav-tab-active';}?>">General <span class="badge badge-important" id="sso_errors"><?php if($status->num_errors != 0) echo $status->num_errors; ?></span></a><?php } if ($show_idp) { ?><a href="?page=sso_idp.php" class="nav-tab<?php if($tab == 'sso_idp.php'){echo ' nav-tab-active';}?>">Identity Provider</a><?php } if ($show_sp) { ?><a href="?page=sso_sp.php" class="nav-tab<?php if($tab == 'sso_sp.php'){echo ' nav-tab-active';}?>">Service Provider</a><?php } ?> <a href="?page=sso_help.php" class="nav-tab<?php if($tab == 'sso_help.php'){echo ' nav-tab-active';}?>">Help</a> </h2> </div>
Hi all,
I’ve tried the saml-20-single-sign-on plugin on wordpress 3.6.1 in multisite mode…
At first, I have to say that I’ve been able to do a basic SAML configuration and made all sites authenticate or not throught one SAML instance…
(After I’ve made this https://www.ads-software.com/support/topic/configuration-is-broken-on-multisite)Unfortunately, I was unable to achieve a specific blog SAML configuration, I mean one site authenticate throught SAML and all others or some with the usual wordpress login scheme…
It was for me a kind weird as there is already a lots of works in the plugin that let me thinks that specific blog SAML authentication configuration is a built in fonctionnality…– wp_[blog_id]_options saml_authentication_options
– specific blog saml configuration files /wp-content/blogs.dir/[blog_id]/files/saml-20-single-sign-on
– authsources.php file containing current blog id
– and so on…I hope to have done something wrong, but until I find what… I’ve make it work by myself…
If specific blog SAML configurations is suppose to workout without any plugin modifications…
You’re welcome to point me out some possible mistakes I’ve maybe done during the plugin installation… (I’m not a wordpress expert so…)Meanwhile, here is how I’ve been able to make work specifics SAML configuration for a particular blog…
(It’s a kind of work in progress as this seem’s to work for me, but it is certainly not a complete and clean solution)** At first, I’ve followed the installation instructions from the wordpress plugin web site.
After that, I made the modification proposed by Ben Overmyer, https://www.ads-software.com/support/topic/configuration-is-broken-on-multisite.
Here is the content of my /wp-content/plugins/saml-20-single-sign-on/lib/views/nav_tabs.php after the Ben Overmyer suggestion:<?php $tab = $_GET['page']; $is_multisite = is_multisite(); $is_network_admin_page = is_network_admin(); if ($is_network_admin_page && $is_multisite) { $show_general = false; $show_sp = false; $show_idp = true; } elseif (!$is_network_admin_page && $is_multisite) { $show_general = true; $show_sp = true; $show_idp = false; } else { $show_general = true; $show_sp = true; $show_idp = true; } ?> <link rel="stylesheet" href="<?php echo constant('SAMLAUTH_URL') . '/lib/css/sso.css';?>" /> <link href="//netdna.bootstrapcdn.com/font-awesome/3.1.1/css/font-awesome.css" rel="stylesheet"> <div class="wrap"> <h2 class="nav-tab-wrapper"> Single Sign-On <?php if ($show_general) { ?><a href="?page=sso_general.php" class="nav-tab<?php if($tab == 'sso_general.php'){echo ' nav-tab-active';}?>">General <span class="badge badge-important" id="sso_errors"><?php if($status->num_errors != 0) echo $status->num_errors; ?></span></a><?php } if ($show_idp) { ?><a href="?page=sso_idp.php" class="nav-tab<?php if($tab == 'sso_idp.php'){echo ' nav-tab-active';}?>">Identity Provider</a><?php } if ($show_sp) { ?><a href="?page=sso_sp.php" class="nav-tab<?php if($tab == 'sso_sp.php'){echo ' nav-tab-active';}?>">Service Provider</a><?php } ?> <a href="?page=sso_help.php" class="nav-tab<?php if($tab == 'sso_help.php'){echo ' nav-tab-active';}?>">Help</a> </h2> </div>
** To support multiple blog sP, I’ve been force to modify the /wp-content/plugins/saml-20-single-sign-on/saml/config/authsources.php file like this to iterate throught each blog saml_authentication_option:
<?php global $wpdb; $arr = $wpdb->get_results($wpdb->prepare("SELECT blog_id, domain, path FROM wp_blogs where blog_id > 1")); foreach($arr as $blog) { $blog_id = $blog->blog_id; $wp_opt = get_blog_option( $blog_id, 'saml_authentication_options'); // It's probably not the best way to retrieve the proper entity id, but it work! // Originaly, the entityID is left to NULL, but it result in a non proper blog metadata URL that made SAML said that the candidate is not proper for the sP $path = "https://".$blog->domain.$blog->path; $blogentityid = $path."wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/metadata.php/".$blog_id; $config = array( // This is a authentication source which handles admin authentication. 'admin' => array( // The default is to use core:AdminPassword, but it can be replaced with // any authentication source. 'core:AdminPassword', ), // An authentication source which can authenticate against both SAML 2.0 // and Shibboleth 1.3 IdPs. $blog_id => array( 'saml:SP', 'NameIDPolicy' => $wp_opt['nameidpolicy'], // The entity ID of this SP. // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. 'entityID' => $blogentityid, 'sign.authnrequest' => TRUE, 'sign.logout' => TRUE, 'redirect.sign' => TRUE, // The entity ID of the IdP this should SP should contact. // Can be NULL/unset, in which case the user will be shown a list of available IdPs. 'idp' => $wp_opt['idp'] ) ); // Cert and Key may not exist if( file_exists( constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.cer') ) { $config[$blog_id]['certificate'] = constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.cer'; } if( file_exists( constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.key') ) { $config[$blog_id]['privatekey'] = constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.key'; } }
** As the plugin idPs is declared at the website root, I’ve been force to modify the metadata of my SAML idP provider(saml20-sp-remote.php) to point out at the root of the wordpress web site.
It’s kind of weird to do this, but the only solution I know to correct this is to create a virtual folder to the root iDp in the blog folder… But, at first it seem’s to be a lot’s of work for my tests…$metadata['https://[www.wordpresshost.com]/ressources/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/metadata.php/[blog_id]'] = array ( 'entityid' => 'https://[www.wordpresshost.com]/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/saml2-acs.php/16', 'metadata-set' => 'shib13-sp-remote', 'AssertionConsumerService' => array ( 0 => array ( 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', 'Location' => 'https://[www.wordpresshost.com]/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/saml2-acs.php/[blog_id]', 'index' => 0, ), 1 => array ( 'Binding' => 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post', 'Location' => 'https://[www.wordpresshost.com]/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/saml2-acs.php/[blog_id]', 'index' => 1, ), 2 => array ( 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact', 'Location' => 'https://[www.wordpresshost.com]/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/saml2-acs.php/[blog_id]', 'index' => 2, ), 3 => array ( 'Binding' => 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01', 'Location' => 'https://[www.wordpresshost.com]/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/saml2-acs.php/[blog_id]/artifact', 'index' => 3, ), 4 => array ( 'Binding' => 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser', 'Location' => 'https://[www.wordpresshost.com]/wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/saml2-acs.php/[blog_id]', 'index' => 4, ), ), 'certData' => '[YourCertData]', );
** To have a proper blog supported idP definition, I’ve created a file /wp-content/blogs.dir/[blog_id]/files/saml-20-single-sign-on/etc/config/saml20-idp-remote.ini with a proper idP definition.
In my installation, this file is not copied by default into the blog plugin folder and this result in error message in the sso_general.php blog page saying that we need to change default idP settings…
Once I’ve placed this file in the blog saml setting folder, error messages went away![https://www.samlhost.com] name = "samlhost" SingleSignOnService = "https://[www.samlhost.com]/simplesamlphp/saml2/idp/SSOService.php" SingleLogoutService = "https://[www.samlhost.com]/simplesamlphp/saml2/idp/SingleLogoutService.php" certFingerprint = "[YourCertFingerPrint]"
** I don’t know why, but I had to change views form post actions to work with blog sub folder… it was like if URL was originaly not relatives…
1- Here is the list of all affected files: /wp-content/plugins/saml-20-single-sign-on/lib/views/[sso_sp.php, sso_idp.php, sso_general.php] 2- Briefly, I've simply change all form tag to <form method="post" action="..<?php echo $_SERVER['PHP_SELF'] . '?page=' . basename(__FILE__); ?>&updated=true" enctype="multipart/form-data">...
** I’ve done again the blog saml settings to be sure that the proper SAML provider settings are correct
After that, I’ve been able to achieve a successful SAML login on one specific blog
## IMPORTANT ##
This walkthrought is suppose to work for blogs where you manualy put the /wp-content/blogs.dir/[blog_id]/files/saml-20-single-sign-on/etc/config/saml20-idp-remote.ini file in as at this time the plugin don’t copy or create this required file automaticaly
(At least on my installation)For authsources.php above, the foreach loop is not necessary and only works for the last site added since $config is overwritten each iteration. The following can be used instead. Also, removed direct SQL queries.
$blog_id = (string)get_current_blog_id(); $wp_opt = get_blog_option($blog_id, 'saml_authentication_options'); $blog_entityid = NULL; $blog_details = get_blog_details($blog_id); if ( !empty( $blog_details ) ) { $blog_entityid = $blog_details->siteurl . $blog_details->path . "wp-content/plugins/saml-20-single-sign-on/saml/www/module.php/saml/sp/metadata.php/" . $blog_id; } $config = array( // This is a authentication source which handles admin authentication. 'admin' => array( // The default is to use core:AdminPassword, but it can be replaced with // any authentication source. 'core:AdminPassword', ), // An authentication source which can authenticate against both SAML 2.0 // and Shibboleth 1.3 IdPs. $blog_id => array( 'saml:SP', 'NameIDPolicy' => $wp_opt['nameidpolicy'], // The entity ID of this SP. // Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. 'entityID' => $blog_entityid, 'sign.authnrequest' => TRUE, 'sign.logout' => TRUE, 'redirect.sign' => TRUE, // The entity ID of the IdP this should SP should contact. // Can be NULL/unset, in which case the user will be shown a list of available IdPs. 'idp' => $wp_opt['idp'] ) ); // Cert and Key may not exist if( file_exists( constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.cer') ) { $config[$blog_id]['certificate'] = constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.cer'; } if( file_exists( constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.key') ) { $config[$blog_id]['privatekey'] = constant('SAMLAUTH_CONF') . '/certs/' . $blog_id . '/' . $blog_id . '.key'; }
- The topic ‘Configuration is broken on Multisite’ is closed to new replies.