Commit 1638ee7e authored by haemmer's avatar haemmer
Browse files

Fixed #275 as well as some other minor bugs

parent 65b6ae1c
<?php <?php
// WAYF Identity Provider Configuration file // WAYF Identity Provider Configuration file
// In the following you see some example entries of Identity Providers and // Find below some example entries of Identity Providers, categories and
// cascaded WAYFs // cascaded WAYFs
// The keys of $IDProviders must correspond to the entityId of the // The keys of $IDProviders must correspond to the entityId of the
// Identity Providers or a unique value in case of a cascaded WAYF/DS or // Identity Providers or a unique value in case of a cascaded WAYF/DS or
// a category // a category. In the case of a category, the key must correspond to the the
// Type value of Identity Provider entries.
// The sequence of IdPs and SPs play a role. No sorting is done. // The sequence of IdPs and SPs play a role. No sorting is done.
// A general entry for an IdP can consist of the form: // A general entry for an IdP can consist of the form:
// Type: [Optional] Some type that is used for the embedded wayf to hide // Type: [Optional] Type of the entry. Default type will
// or show certain categories. Default type will
// be 'unknown' if not specified. // be 'unknown' if not specified.
// Categories should have the type 'category'
// An entry for a cascaded WAYF that the user shall be
// redirected to should have the type 'wayf'
// Name: [Mandatory] Default name to display in drop-down list // Name: [Mandatory] Default name to display in drop-down list
// [en|it|fr||de|pt][Name]: [Optional] Display name in other languages // [en|it|fr||de|pt][Name]: [Optional] Display name in other languages
// SSO: [Mandatory] Should be the SAML1 SSO endpoint of the IdP // SSO: [Mandatory] Should be the SAML1 SSO endpoint of the IdP
// Realm: [Optional] Kerberos Realm // Realm: [Optional] Kerberos Realm
// IP[]: [Optional] IP ranges of that organizations that can be used to guess // IP[]: [Optional] IP ranges of that organizations that can be used to guess
// a user's Identity Provider // a user's Identity Provider
// Index: [Optional] An alphanumerical value that is used for sorting
// An entry for another WAYF that the user shall be redirected to should have: // categories and Identity Provider in ascending order
// Type: 'wayf' // if the Identity Providers are parsed from metadata.
// This is only relevant if
// $includeLocalConfEntries = true
// A category entry can be used to group multiple IdP entries into a optgroup // A category entry can be used to group multiple IdP entries into a optgroup
// The category entries should look like: // The category entries should look like:
...@@ -59,7 +64,7 @@ $IDProviders['aitta.funet.fi'] = array ( ...@@ -59,7 +64,7 @@ $IDProviders['aitta.funet.fi'] = array (
// Category // Category
$IDProviders['vho'] = array ( $IDProviders['vho'] = array (
'Type' => 'category', 'Type' => 'category',
'Name' => 'Virtual Home Organization', 'Name' => 'Virtual Home Organizations',
); );
// An example of a configuration with multiple network blocks and multiple languages // An example of a configuration with multiple network blocks and multiple languages
...@@ -107,10 +112,10 @@ $IDProviders['other'] = array ( ...@@ -107,10 +112,10 @@ $IDProviders['other'] = array (
// Standard example with a Type that could be used to hide certain // Standard example with a Type that could be used to hide certain
// Identity Providers in the list of an embedded WAYF according to their type // Identity Providers in the list of an embedded WAYF according to their type
$IDProviders['https://toba.switch.ch/idp/shibboleth'] = array( $IDProviders['https://aai-logon.switch.ch/idp/shibboleth'] = array(
'Type' => 'other', 'Type' => 'other',
'Name' => 'SWITCH - Serving Swiss Universities', 'Name' => 'SWITCH - Serving Swiss Universities',
'SSO' => 'https://toba.switch.ch/idp/profile/Shibboleth/SSO', 'SSO' => 'https://aai-logon.switch.ch/idp/profile/Shibboleth/SSO',
); );
?> ?>
...@@ -8,7 +8,23 @@ Bug reports/feature requests: https://forge.switch.ch/redmine/projects/wayf/issu ...@@ -8,7 +8,23 @@ Bug reports/feature requests: https://forge.switch.ch/redmine/projects/wayf/issu
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Description: Description:
The SWITCHwayf is an implementation of the Shibboleth WAYF and SAML2 Discovery Service protocol for use withing a Shibboleth architecture. The SWITCHwayf is an implementation of the Shibboleth WAYF and SAML2 Discovery
Service protocol for use withing a Shibboleth architecture.
-------------------------------------------------------------------------------
Security Note (25. October 2010):
The current implementation of the Discovery Service protocol as defined in
http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-idp-discovery.pdf
states that the protocol creates opportunities for phishing attacks as do all
SSO protocols that make use of redirection. Therefore, the specification states
that an implementation should examine the 'return' parameter used in a
Discovery Service request and match it against the <idpdisc:DiscoveryResponse>
extension in SAML metadata. The implementation of the Discovery Service protocol
in the SWITCHwayf does NOT verify the return parameter because it only
optionally reads SAML metadata.
Thanks to Tom Scavo for making us aware of this issue.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -29,6 +45,7 @@ Some of the features include ...@@ -29,6 +45,7 @@ Some of the features include
- HTML code generation for embedding the WAYF directly into a web page - HTML code generation for embedding the WAYF directly into a web page
- Support for remembering IdP selection permanently - Support for remembering IdP selection permanently
- I18N support, currently language packs for en, de, it, fr and pt are included - I18N support, currently language packs for en, de, it, fr and pt are included
- Support for templates
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -211,7 +228,7 @@ Credits for this feature go to Josh Howlett from Bristol University. ...@@ -211,7 +228,7 @@ Credits for this feature go to Josh Howlett from Bristol University.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Identity Provider configuration file format: Configuration file format:
Checkout the file 'IDProvider.conf.php' for an example of the file format. It's Checkout the file 'IDProvider.conf.php' for an example of the file format. It's
supposed to be mostly self-explanatory. Basically the file format is PHP code supposed to be mostly self-explanatory. Basically the file format is PHP code
that defines an array of arrays called $IDProviders. that defines an array of arrays called $IDProviders.
...@@ -221,34 +238,64 @@ Identity Providers or a unique value in case of a cascaded WAYF/DS or ...@@ -221,34 +238,64 @@ Identity Providers or a unique value in case of a cascaded WAYF/DS or
a category. The entityID must be a valid URI (URL or URN) where in the a category. The entityID must be a valid URI (URL or URN) where in the
case of a URN the last component must be a valid hostname. case of a URN the last component must be a valid hostname.
The sequence of IdPs and SPs matters and no sorting is done. If metadata is not parsed from SAML2 metadta (using the setting
$useSAML2Metadata = false), the IdPs and category entries will be displayed
A general entry for an IdP can consist of the form: in order as defined in the configuration file and no sorting is done.
Type: [Optional] Some type that is used for the embedded wayf to hide
or show certain categories. Default type will If metadata is used ($useSAML2Metadata = true) to generate the list of Identity
be 'unknown' if not specified. Providers, the Identity Providers will first be sorted according to their
Name: [Mandatory] Default name to display in drop-down list type/category, their Index value (see below) and then alphabetically after their
[en|it|fr||de|pt][Name]: [Optional] Display name in other languages (local) Name within the same type category.
SSO: [Mandatory] Should be the SAML1 SSO endpoint of the IdP If an IdP does not have a type, its category is 'unknown'.
Realm: [Optional] Kerberos Realm If there exists a type for an IdP that does not have a corresponding category
IP[]: [Optional] IP ranges of that organizations that can be used to it will be displayed in the category 'unknown' at the end of the drop down list
guess a user's Identity Provider but will keep its type value (this is important for the Embedded Discovery
Service).
An entry for another WAYF that the user shall be redirected to should have:
Type: 'wayf' A general entry for an Identity Provider, a cascaded WAYF/DS or a category is
of the following form:
A category entry can be used to group multiple IdP entries into a optgroup $IDProviders[#key#] = #entry#
The category entries should look like:
Name: [Mandatory] Default name to display in drop-down list #key# is a unique value that must correspond to the entity's entityID in case
[en|it|fr||de|pt][Name]: [Optional] Display name in other languages the entry stands for an Identity Provider. For entries of Type category, the
Type: 'category' Category type #key# should be an identifier that corresponds to a 'Type' of an IdP.
As stated above, the sequence of entries is important. So, one is completely #entry# is another hash array with the following keys:
flexible when it comes to ordering the category and IdP entries. ['Type']: Optional Type that is used for the embedded wayf to hide
or show certain categories. Default type will
be 'unknown' if not specified.
An entry for another WAYF/DS that the user shall be
redirected to should have ['Type'] ='wayf
The Type values 'category' and 'wayf' are reserved
words that are not allowed to be assigned to
entries for Identity Providers.
['Name']: Mandatory Default name to display in drop-down list
['en'|'it'|'fr'|'de'|'pt']['Name']:
Optional Display name in other languages
['SSO']: Mandatory Should be the SAML1 SSO endpoint of the IdP
['Realm']: Optional Kerberos Realm
['IP'][]: Optional IP ranges of that organizations that can be used to
guess a user's Identity Provider
['Index']: Optional An alphanumerical value that is used for sorting
categories and Identity Provider in ascending order
if the Identity Providers are parsed from metadata.
This is only relevant if
$includeLocalConfEntries = true
For category entries, only Type, (local) Name and Index are relevant.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Changes: Changes:
1.14 - Sorting within categories works now correctly if SAML2 metadata is
used to generate Identity Provider drop-down list. Thanks to Prof.
Kazu Yamaji from NII for reporting this issue.
- Fixed a minor bug in templates.php that cause PHP warnings to show up
in case an invalid IdP was stored in the cookie.
- Fixed a bug affecting the Kerberos authentication.
Thanks to Robert Basch from MIT for reporting these bugs and for
submitting patches.
- Fixed a bug where hidden IdPs would still be shown in Embedded WAYF
1.13 - Added Favourite IdPs to Embedded WAYF 1.13 - Added Favourite IdPs to Embedded WAYF
- Fixed a bug where the state of the "Remember for session" checkbox was - Fixed a bug where the state of the "Remember for session" checkbox was
not remembered. not remembered.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
****************************************************************************** ******************************************************************************
SWITCH PHP WAYF, SWITCH PHP WAYF,
Copyright 2009 SWITCH - Serving Swiss Universities Copyright 2009 SWITCH - Serving Swiss Universities
Version: 1.13 Version: 1.14
Contact: aai@switch.ch Contact: aai@switch.ch
Web site: http://www.switch.ch/aai/wayf Web site: http://www.switch.ch/aai/wayf
****************************************************************************** ******************************************************************************
...@@ -14,7 +14,7 @@ Web site: http://www.switch.ch/aai/wayf ...@@ -14,7 +14,7 @@ Web site: http://www.switch.ch/aai/wayf
// Load general configuration and template file // Load general configuration and template file
/*------------------------------------------------*/ /*------------------------------------------------*/
require_once('config.php'); require_once('config.test.php');
require_once('templates.php'); require_once('templates.php');
require_once('functions.php'); require_once('functions.php');
require_once('languages.php'); require_once('languages.php');
...@@ -386,6 +386,18 @@ if ($hintedCookieIdP != '-'){ ...@@ -386,6 +386,18 @@ if ($hintedCookieIdP != '-'){
$selectedIDP = '-'; $selectedIDP = '-';
} }
/*------------------------------------------------*/
// Sort Identity Providers
/*------------------------------------------------*/
//if (isset($useSAML2Metadata) && $useSAML2Metadata){
if (true){
// Only automatically sort if list of Identity Provider is parsed
// from metadata instead of being manualy managed
sortIdentityProviders($IDProviders);
}
/*------------------------------------------------*/ /*------------------------------------------------*/
// Draw WAYF // Draw WAYF
/*------------------------------------------------*/ /*------------------------------------------------*/
......
...@@ -45,16 +45,20 @@ $SPCookieName = $cookieNamePrefix.'_saml_sp'; ...@@ -45,16 +45,20 @@ $SPCookieName = $cookieNamePrefix.'_saml_sp';
// Whether to show the checkbox to permanently remember a setting // Whether to show the checkbox to permanently remember a setting
$showPermanentSetting = false; $showPermanentSetting = false;
// Set to true in order to enable dynamic generation of the IdP list displayed // Set to true in order to enable reading the Identity Provider from a SAML2
// metadata file defined below in $metadataFile
$useSAML2Metadata = false; $useSAML2Metadata = false;
// Parsed metadata shall have precedence // If ture parsed metadata shall have precedence if there are entries defined
// when conflicts between SAML2 metadata and local IDProvider.conf are detected. // in metadata as well as the local IDProviders configuration file.
// Only relevant if $useSAML2Metadata is true
$SAML2MetaOverLocalConf = false; $SAML2MetaOverLocalConf = false;
// If includeLocalConfEntries parameter is set to true, mergeInfo() will also consider IDPs // If includeLocalConfEntries parameter is set to true, Identity Providers
// not listed in metadataIDProviders but defined in IDProviders file // not listed in metadata but defined in the local IDProviders file will also
// This is required if you need to add local exceptions over the federation metadata // be displayed in the drop down list. This is required if you need to add
// local exceptions over the federation metadata
// Only relevant if $useSAML2Metadata is true
$includeLocalConfEntries = true; $includeLocalConfEntries = true;
// Whether to turn on Kerberos support for IdP preselection // Whether to turn on Kerberos support for IdP preselection
...@@ -128,6 +132,6 @@ $WAYFLogFile = '/var/log/apache2/wayf.log'; ...@@ -128,6 +132,6 @@ $WAYFLogFile = '/var/log/apache2/wayf.log';
// Development mode settings // Development mode settings
//************************** //**************************
// If the development mode is activated, PHP errors and warnings will be displayed // If the development mode is activated, PHP errors and warnings will be displayed
$developmentMode = true; $developmentMode = false;
?> ?>
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
--> -->
</style> </style>
</head> </head>
<body bgcolor="#ffffff" onLoad="if (document.IdPList && document.IdPList.Select) document.IdPList.Select.focus()"> <body bgcolor="#ffffff" onLoad="if (top != self) {top.location = self.location;};if (document.IdPList && document.IdPList.Select) document.IdPList.Select.focus()">
<script language="JavaScript" type="text/javascript"> <script language="JavaScript" type="text/javascript">
<!-- <!--
function showConfirmation(){ function showConfirmation(){
......
...@@ -344,7 +344,7 @@ function getIPAdressHint() { ...@@ -344,7 +344,7 @@ function getIPAdressHint() {
global $IDProviders; global $IDProviders;
foreach($IDProviders as $name => $idp) { foreach($IDProviders as $name => $idp) {
if (array_key_exists("IP", $idp)) { if (is_array($idp) && array_key_exists("IP", $idp)) {
$clientIP = $_SERVER["REMOTE_ADDR"]; $clientIP = $_SERVER["REMOTE_ADDR"];
foreach( $idp["IP"] as $network ) { foreach( $idp["IP"] as $network ) {
...@@ -511,4 +511,90 @@ function convertToShibDSStructure($IDProviders){ ...@@ -511,4 +511,90 @@ function convertToShibDSStructure($IDProviders){
} }
/******************************************************************************/
// Sorts the IDProviders array
function sortIdentityProviders(&$IDProviders){
$sortedIDProviders = Array();
$sortedCategories = Array();
foreach ($IDProviders as $entityId => $IDProvider){
if (!is_array($IDProvider)){
// Remove any entries that are not arrays
unset($IDProviders[$entityId]);
} elseif ($IDProvider['Type'] == 'category'){
$sortedCategories[$entityId] = $IDProvider;
} else {
$sortedIDProviders[$entityId] = $IDProvider;
}
}
// Sort categories and IdPs
if (count($sortedCategories) > 1){
// Sort using index
uasort($sortedCategories, 'sortUsingTypeIndexAndName');
} else {
// Sort alphabetically using the key of a category
ksort($sortedCategories);
}
// Add category 'unknown' if not present
if (!isset($IDProviders['unknown'])){
$sortedCategories['unknown'] = array (
'Name' => 'Unknown',
'Type' => 'category',
);
}
// Sort Identity Providers
uasort($sortedIDProviders, 'sortUsingTypeIndexAndName');
$IDProviders = Array();
// Compose array
$showUnknownCategory = false;
while(list($categoryKey, $categoryValue) = each($sortedCategories)){
$IDProviders[$categoryKey] = $categoryValue;
// Loop through all IdPs
foreach ($sortedIDProviders as $IDProvidersPKey => $IDProvidersValue){
// Add IdP if its type matches the current category
if ($IDProvidersValue['Type'] == $categoryKey){
$IDProviders[$IDProvidersPKey] = $IDProvidersValue;
unset($sortedIDProviders[$IDProvidersPKey]);
}
// Add IdP if its type is 'unknown' or if there doesnt exist a category for its type
if ($categoryKey == 'unknown' || !isset($sortedCategories[$IDProvidersValue['Type']])){
$IDProviders[$IDProvidersPKey] = $IDProvidersValue;
unset($sortedIDProviders[$IDProvidersPKey]);
$showUnknownCategory = true;
}
}
}
// Check if unkown category is needed
if (!$showUnknownCategory){
unset($IDProviders['unknown']);
}
}
/******************************************************************************/
// Sorts two entries according to their Type, Index and (local) Name
function sortUsingTypeIndexAndName($a, $b){
global $language;
if ($a['Type'] != $b['Type']){
return strcmp($b['Type'], $a['Type']);
} elseif (isset($a['Index']) && isset($b['Index']) && $a['Index'] != $b['Index']){
return strcmp($a['Index'], $b['Index']);
} else {
// Sort using locale names
$localNameB = (isset($a[$language]['Name'])) ? $a[$language]['Name'] : $a['Name'];
$localNameA = (isset($b[$language]['Name'])) ? $b[$language]['Name'] : $b['Name'];
return strcmp($localNameB, $localNameA);
}
}
?> ?>
...@@ -173,9 +173,6 @@ function parseMetadata($metadataFile, $defaultLanguage){ ...@@ -173,9 +173,6 @@ function parseMetadata($metadataFile, $defaultLanguage){
} }
} }
// Sort IdPs
uasort($metadataIDProviders, 'sortIdPs');
return $metadataIDProviders; return $metadataIDProviders;
} }
...@@ -216,12 +213,6 @@ function dumpFile($metadataIDPFile, $IDProviders){ ...@@ -216,12 +213,6 @@ function dumpFile($metadataIDPFile, $IDProviders){
} }
} }
/******************************************************************************/
// Sort IdP array using the default name of an IdP
function sortIdPs($a, $b){
return strcmp($a['Name'], $b['Name']);
}
/******************************************************************************/ /******************************************************************************/
// Function mergeInfo is used to create the effective $IDProviders array. // Function mergeInfo is used to create the effective $IDProviders array.
...@@ -233,33 +224,38 @@ function mergeInfo($IDProviders, $metadataIDProviders, $SAML2MetaOverLocalConf, ...@@ -233,33 +224,38 @@ function mergeInfo($IDProviders, $metadataIDProviders, $SAML2MetaOverLocalConf,
// If $includeLocalConfEntries parameter is set to true, mergeInfo() will also consider IDPs // If $includeLocalConfEntries parameter is set to true, mergeInfo() will also consider IDPs
// not listed in metadataIDProviders but defined in IDProviders file // not listed in metadataIDProviders but defined in IDProviders file
// This is required if you need to add local exceptions over the federation metadata // This is required if you need to add local exceptions over the federation metadata
$arrayOfIDPs = $metadataIDProviders; $allIDPS = $metadataIDProviders;
$mergedArray = Array();
if ($includeLocalConfEntries) { if ($includeLocalConfEntries) {
$arrayOfIDPs = array_merge($metadataIDProviders, $IDProviders); $allIDPS = array_merge($metadataIDProviders, $IDProviders);
uasort($arrayOfIDPs, 'sortIdPs');
} }
foreach ($arrayOfIDPs as $meta => $metaArray){ foreach ($allIDPS as $allIDPsKey => $allIDPsEntry){
if(isset($IDProviders[$allIDPsKey])){
// Skip IDPs // Entry exists also in local IDProviders.conf.php
if ( if (isset($metadataIDProviders[$allIDPsKey]) && is_array($metadataIDProviders[$allIDPsKey])) {
!$SAML2MetaOverLocalConf &&
isset($IDProviders[$meta]) // Remove IdP if there is a removal rule in local IDProviders.conf.php
&& !is_array($IDProviders[$meta]) if (!is_array($IDProviders[$allIDPsKey])){
) { continue; } unset($metadataIDProviders[$allIDPsKey]);
continue;
if(isset($IDProviders[$meta])){ }
if (isset($metadataIDProviders[$meta]) && is_array($metadataIDProviders[$meta])) {
if($SAML2MetaOverLocalConf){ // Entry exists in both IDProviders sources and is an array
$mergedArray[$meta] = array_merge($IDProviders[$meta], $metadataIDProviders[$meta]); if($SAML2MetaOverLocalConf){
} else { // Metadata entry overwrite local conf
$mergedArray[$meta] = $metadataIDProviders[$meta]; $mergedArray[$allIDPsKey] = array_merge($IDProviders[$allIDPsKey], $metadataIDProviders[$allIDPsKey]);
} } else {
} else { // Local conf overwrites metada entry
$mergedArray[$meta] = $IDProviders[$meta]; $mergedArray[$allIDPsKey] = array_merge($metadataIDProviders[$allIDPsKey], $IDProviders[$allIDPsKey]);
} }
} else {
// Entry only exists in local IDProviders file
$mergedArray[$allIDPsKey] = $IDProviders[$allIDPsKey];
}
} else { } else {
$mergedArray[$meta] = $metadataIDProviders[$meta]; // Entry doesnt exist in in local IDProviders.conf.php
$mergedArray[$allIDPsKey] = $metadataIDProviders[$allIDPsKey];
} }
} }
......
...@@ -226,19 +226,26 @@ function printEmbeddedWAYFScript(){ ...@@ -226,19 +226,26 @@ function printEmbeddedWAYFScript(){
// Generate list of Identity Providers // Generate list of Identity Providers
$JSONIdPArray = array(); $JSONIdPArray = array();
foreach ($IDProviders as $key => $value){ foreach ($IDProviders as $key => $IDProvider){
// Get IdP Name // Get IdP Name
if (isset($value[$language]['Name'])){ if (isset($IDProvider[$language]['Name'])){
$IdPName = addslashes($value[$language]['Name']); $IdPName = addslashes($IDProvider[$language]['Name']);
} else { } else {
$IdPName = addslashes($value['Name']); $IdPName = addslashes($IDProvider['Name']);
} }
// Set selected attribute // Set selected attribute
$selected = ($selectedIDP == $key) ? ' selected="selected"' : '' ; $selected = ($selectedIDP == $key) ? ' selected="selected"' : '' ;
$IdPType = isset($IDProviders[$key]['Type']) ? $IDProviders[$key]['Type'] : ''; $IdPType = isset($IDProviders[$key]['Type']) ? $IDProviders[$key]['Type'] : '';
// SSO
if (isset($IDProvider['SSO'])){
$IdPSSO = $IDProvider['SSO'];
} else {
$IdPSSO = '';
}
// Skip non-IdP entries // Skip non-IdP entries
if ($IdPType == '' || $IdPType == 'category'){ if ($IdPType == '' || $IdPType == 'category'){
continue; continue;
...@@ -249,7 +256,7 @@ function printEmbeddedWAYFScript(){ ...@@ -249,7 +256,7 @@ function printEmbeddedWAYFScript(){
"{$key}":{ "{$key}":{
type:"{$IdPType}", type:"{$IdPType}",
name:"{$IdPName}", name:"{$IdPName}",
SAML1SSOurl:"{$value['SSO']}" SAML1SSOurl:"{$IdPSSO}"
} }
ENTRY; ENTRY;
} }
...@@ -858,20 +865,20 @@ SCRIPT; ...@@ -858,20 +865,20 @@ SCRIPT;
// Generate drop-down list // Generate drop-down list
$optgroup = ''; $optgroup = '';
foreach ($IDProviders as $key => $value){ foreach ($IDProviders as $key => $IDProvider){
// Get IdP Name // Get IdP Name
if (isset($value[$language]['Name'])){ if (isset($IDProvider[$language]['Name'])){
$IdPName = addslashes($value[$language]['Name']); $IdPName = addslashes($IDProvider[$language]['Name']);
} else { } else {
$IdPName = addslashes($value['Name']); $IdPName = addslashes($IDProvider['Name']);
} }
// Figure out if entry is valid or a category // Figure out if entry is valid or a category
if (!isset($value['SSO'])){ if (!isset($IDProvider['SSO'])){
// Check if entry is a category // Check if entry is a category
if (isset($value['Type']) && $value['Type'] == 'category'){ if (isset($IDProvider['Type']) && $IDProvider['Type'] == 'category'){
echo <<<SCRIPT echo <<<SCRIPT
......