\n";
foreach ($IDProviders as $key => $value){
if (isset($value['SSO'])){
$message .= $key."
\n";
}
}
$message .= "\n";
printError($message);
exit;
}
}
/******************************************************************************/
// Validates the URL format and returns the URL without GET arguments and fragment
function verifyAndStripReturnURL($url){
$components = parse_url($url);
if (!$components){
return false;
}
$recomposedURL = $components['scheme'].'://';
if (isset($components['user'])){
$recomposedURL .= $components['user'];
if (isset($components['pass'])){
$recomposedURL .= ':'.$components['pass'];
}
$recomposedURL .= '@';
}
if (isset($components['host'])){
$recomposedURL .= $components['host'];
}
if (isset($components['port'])){
$recomposedURL .= ':'.$components['port'];
}
if (isset($components['path'])){
$recomposedURL .= $components['path'];
}
return $recomposedURL;
}
/******************************************************************************/
// Parses the hostname out of a string and returns it
function getHostNameFromURI($string){
// Check if string is URN
if (preg_match('/^urn:mace:/i', $string)){
// Return last component of URN
return end(explode(':', $string));
}
// Apparently we are dealing with something like a URL
if (preg_match('/([a-zA-Z0-9\-\.]+\.[a-zA-Z0-9\-\.]{2,6})/', $string, $matches)){
return $matches[0];
} else {
return '';
}
}
/******************************************************************************/
// Parses the domain out of a string and returns it
function getDomainNameFromURI($string){
// Check if string is URN
if (preg_match('/^urn:mace:/i', $string)){
// Return last component of URN
return getTopLevelDomain(end(explode(':', $string)));
}
// Apparently we are dealing with something like a URL
if (preg_match('/[a-zA-Z0-9\-\.]+\.([a-zA-Z0-9\-\.]{2,6})/', $string, $matches)){
return getTopLevelDomain($matches[0]);
} else {
return '';
}
}
/******************************************************************************/
// Returns top level domain name from a DNS name
function getTopLevelDomain($string){
$hostnameComponents = explode('.', $string);
if (count($hostnameComponents) >= 2){
return $hostnameComponents[count($hostnameComponents)-2].'.'.$hostnameComponents[count($hostnameComponents)-1];
} else {
return $string;
}
}
/******************************************************************************/
// Parses the reverse dns lookup hostname out of a string and returns domain
function getDomainNameFromURIHint(){
global $IDProviders;
$clientHostname = gethostbyaddr($_SERVER['REMOTE_ADDR']);
if ($clientHostname == $_SERVER['REMOTE_ADDR']){
return '-';
}
// Get domain name from client host name
$clientDomainName = getDomainNameFromURI($clientHostname);
if ($clientDomainName == ''){
return '-';
}
// Return first matching IdP entityID that contains the client domain name
foreach ($IDProviders as $key => $value){
if (preg_match('/'.$clientDomainName.'/', $key)){
return $key;
}
}
// No matching entityID was found
return '-';
}
/******************************************************************************/
// Get the user's language using the accepted language http header
function determineLanguage(){
global $langStrings, $defaultLanguage;
// Check if language is enforced by PATH-INFO argument
if (isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO'])){
foreach ($langStrings as $lang => $values){
if (preg_match('#/'.$lang.'($|/)#',$_SERVER['PATH_INFO'])){
return $lang;
}
}
}
// Check if there is a language GET argument
if (isset($_GET['lang'])){
$localeComponents = decomposeLocale($_GET['lang']);
if (
$localeComponents !== false
&& isset($langStrings[$localeComponents[0]])
){
// Return language
return $localeComponents[0];
}
}
// Return default language if no headers are present otherwise
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
return $defaultLanguage;
}
// Inspect Accept-Language header which looks like:
// Accept-Language: en,de-ch;q=0.8,fr;q=0.7,fr-ch;q=0.5,en-us;q=0.3,de;q=0.2
$languages = explode( ',', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']));
foreach ($languages as $language){
$languageParts = explode(';', $language);
// Only treat art before the prioritization
$localeComponents = decomposeLocale($languageParts[0]);
if (
$localeComponents !== false
&& isset($langStrings[$localeComponents[0]])
){
// Return language
return $localeComponents[0];
}
}
return $defaultLanguage;
}
/******************************************************************************/
// Splits up a string (relazed) according to
// http://www.debian.org/doc/manuals/intro-i18n/ch-locale.en.html#s-localename
// and returns an array with the four components
function decomposeLocale($locale){
// Locale name syntax: language[_territory][.codeset][@modifier]
if (!preg_match('/^([a-zA-Z]{2})([-_][a-zA-Z]{2})?(\.[^@]+)?(@.+)?$/', $locale, $matches)){
return false;
} else {
// Remove matched string in first position
array_shift($matches);
return $matches;
}
}
/******************************************************************************/
// Gets a string in the user's language. If no localized version is available
// for the string, the English string is returned as default.
function getLocalString($string, $encoding = ''){
global $defaultLanguage, $langStrings, $language;
$textString = '';
if (isset($langStrings[$language][$string])){
$textString = $langStrings[$language][$string];
} else {
$textString = $langStrings[$defaultLanguage][$string];
}
// Change encoding if necessary
if ($encoding == 'js'){
$textString = convertToJSString($textString);
}
return $textString;
}
/******************************************************************************/
// Converts string to a JavaScript format that can be used in JS alert
function convertToJSString($string){
return addslashes(html_entity_decode($string, ENT_COMPAT, 'UTF-8'));
}
/******************************************************************************/
// Checks if entityID hostname of a valid IdP exists in path info
function getIdPPathInfoHint(){
global $IDProviders;
// Check if path info is available at all
if (!isset($_SERVER['PATH_INFO']) || empty($_SERVER['PATH_INFO'])){
return '-';
}
// Check for entityID hostnames of all available IdPs
foreach ($IDProviders as $key => $value){
// Only check actual IdPs
if (
isset($value['SSO'])
&& !empty($value['SSO'])
&& $value['Type'] != 'wayf'
&& checkPathInfo(getHostNameFromURI($key))
){
return $key;
}
}
// Check for entityID domain names of all available IdPs
foreach ($IDProviders as $key => $value){
// Only check actual IdPs
if (
isset($value['SSO'])
&& !empty($value['SSO'])
&& $value['Type'] != 'wayf'
&& checkPathInfo(getDomainNameFromURI($key))
){
return $key;
}
}
return '-';
}
/******************************************************************************/
// Parses the Kerbores realm out of the string and returns it
function getKerberosRealm($string){
global $IDProviders;
if ($string !='' ) {
// Find a matching Kerberos realm
foreach ($IDProviders as $key => $value){
if ($value['Realm'] == $string) return $key;
}
}
return '-';
}
/******************************************************************************/
// Determines the IdP according to the IP address if possible
function getIPAdressHint() {
global $IDProviders;
foreach($IDProviders as $name => $idp) {
if (is_array($idp) && array_key_exists("IP", $idp)) {
$clientIP = $_SERVER["REMOTE_ADDR"];
foreach( $idp["IP"] as $network ) {
if (isIPinCIDRBlock($network, $clientIP)) {
return $name;
}
}
}
}
return '-';
}
/******************************************************************************/
// Returns true if IP is in IPv4/IPv6 CIDR range
// and returns false otherwise
function isIPinCIDRBlock($cidr, $ip) {
// Split CIDR notation
list ($net, $mask) = split ("/", $cidr);
// Convert to binary string value of 1s and 0s
$netAsBinary = convertIPtoBinaryForm($net);
$ipAsBinary = convertIPtoBinaryForm($ip);
// Return false if netmask and ip are using different protocols
if (strlen($netAsBinary) != strlen($ipAsBinary)){
return false;
}
// Compare the first $mask bits
for($i = 0; $i < $mask; $i++){
// Return false if bits don't match
if ($netAsBinary[$i] != $ipAsBinary[$i]){
return false;
}
}
// If we got here, ip matches net
return true;
}
/******************************************************************************/
// Converts IP in human readable format to binary string
function convertIPtoBinaryForm($ip){
// Handle IPv4 IP
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false){
return base_convert(ip2long($ip),10,2);
}
// Return false if IP is neither IPv4 nor a IPv6 IP
if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false){
return false;
}
// Convert IP to binary structure and return false if this fails
if(($ipAsBinStructure = inet_pton($ip)) === false) {
return false;
}
$numOfBytes = 16;
$ipAsBinaryString = '';
// Convert IP to binary string
while ($numOfBytes > 0){
// Convert current byte to decimal number
$currentByte = ord($ipAsBinStructure[$numOfBytes - 1]);
// Convert currenty byte to string of 1 and 0
$currentByteAsBinary = sprintf("%08b", $currentByte);
// Prepend to rest of IP in binary string
$ipAsBinaryString = $currentByteAsBinary.$ipAsBinaryString;
// Decrease byte counter
$numOfBytes--;
}
return $ipAsBinaryString;
}
/******************************************************************************/
// Returns true if URL could be verified or if no check is necessary, false otherwise
function verifyReturnURL($entityID, $returnURL) {
global $SProviders, $useACURLsForReturnParamCheck;
// If SP has a , check return param
if (isset($SProviders[$entityID]['DSURL'])){
return in_array($returnURL, $SProviders[$entityID]['DSURL']);
}
// If fall back check is enabled, check return param
if (isset($useACURLsForReturnParamCheck) && $useACURLsForReturnParamCheck){
// Return true if no assertion consumer URL is defined to check against
// Should never happend
if (!isset($SProviders[$entityID]['ACURL'])){
return false;
}
$returnURLHostName = getHostNameFromURI($returnURL);
foreach($SProviders[$entityID]['ACURL'] as $ACURL){
if (getHostNameFromURI($ACURL) == $returnURLHostName){
return true;
}
}
// We haven't found a matchin assertion consumer url so we return false
return false;
}
// SP has no and $useACURLsForReturnParamCheck
// is disabled, so we don't check anything
return true;
}
/******************************************************************************/
// Returns a reasonable value for returnIDParam
function getReturnIDParam() {
if (isset($_GET['returnIDParam']) && !empty($_GET['returnIDParam'])){
return $_GET['returnIDParam'];
} else {
return 'entityID';
}
}
/******************************************************************************/
// Returns true if valid Shibboleth 1.x request or Directory Service request
function isValidShibRequest(){
return (isValidShib1Request() || isValidDSRequest());
}
/******************************************************************************/
// Returns true if valid Shibboleth request
function isValidShib1Request(){
if (isset($_GET['shire']) && isset($_GET['target'])){
return true;
} else {
return false;
}
}
/******************************************************************************/
// Returns true if valid Directory Service request
function isValidDSRequest(){
if (isset($_GET['entityID']) && isset($_GET['return'])){
return true;
} else {
return false;
}
}
/******************************************************************************/
// Returns true if valid Directory Service request
function logAccessEntry($protocol, $type, $sp, $idp){
global $WAYFLogFile, $useLogging;
if (!$useLogging){
return;
}
// Let's make sure the file exists and is writable first.
if (is_writable($WAYFLogFile)) {
// Create log entry
$entry = date('Y-m-d H:i:s').' '.$_SERVER['REMOTE_ADDR'].' '.$protocol.' '.$type.' '.$idp.' '.$sp."\n";
// We are opening $filename in append mode.
// The file pointer is at the bottom of the file hence
// that's where $somecontent will go when we fwrite() it.
if (!$handle = fopen($WAYFLogFile, 'a')) {
return;
}
// Try getting lock
while (!flock($handle, LOCK_EX)){
usleep(rand(10, 100));
}
// Write $somecontent to our opened file.
fwrite($handle, $entry);
// Release the lock
flock($handle, LOCK_UN);
// Close file handle
fclose($handle);
}
}
/******************************************************************************/
// Returns true if PATH info indicates a request of type $type
function isRequestType($type){
// Make sure the type is checked at end of path info
return checkPathInfo($type.'$');
}
/******************************************************************************/
// Checks for substrings in Path Info and returns true if match was found
function checkPathInfo($needle){
if (
isset($_SERVER['PATH_INFO'])
&& !empty($_SERVER['PATH_INFO'])
&& preg_match('|/'.$needle.'|', $_SERVER['PATH_INFO'])){
return true;
} else {
return false;
}
}
/******************************************************************************/
// Converts to the unified datastructure that the Shibboleth DS will be using
function convertToShibDSStructure($IDProviders){
global $federationName;
$ShibDSIDProviders['identityProviders'] = array();
foreach ($IDProviders as $key => $value){
// Skip unknown and category entries
if(
!isset($value['Type'])
|| $value['Type'] == 'category'
|| $value['Type'] == 'wayf'
){
continue;
}
// Init and fill IdP data
$identityProvider = array();
$identityProvider['entityID'] = $key;
$identityProvider['shibSSOEndpoint'] = $value['SSO'];
$identityProvider['displayNames'][] = array('lang' => 'en', 'name' => $value['Name']);
$identityProvider['attributes'][] = array(
'name' => 'type', 'value' => $value['Type']
);
// Add displayNames in other languages
foreach($value as $lang => $name){
if(
$lang == 'Name'
|| $lang == 'SSO'
|| $lang == 'Realm'
|| $lang == 'Type'
|| $lang == 'IP'
){
continue;
}
if (isset($name['Name'])){
$identityProvider['displayNames'][] = array('lang' => $lang, 'name' => $name['Name']);
}
}
// Add kerberos realm
if(isset($value['Realm'])){
$identityProvider['attributes'][] = array(
'name' => 'kerberosRealm', 'value' => $value['Realm']
);
}
// Add IP ranges
if(isset($value['IP'])){
$identityProvider['attributes'][] = array(
'name' => 'IP', 'value' => $value['IP']
);
}
// Add data to ShibDSIDProviders
$ShibDSIDProviders['identityProviders'][] = $identityProvider;
}
return $ShibDSIDProviders;
}
/******************************************************************************/
// Sorts the IDProviders array
function sortIdentityProviders(&$IDProviders){
$sortedIDProviders = Array();
$sortedCategories = Array();
foreach ($IDProviders as $entityId => $IDProvider){
if (!is_array($IDProvider) || !isset($IDProvider['Name'])){
// 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
$unknownCategoryIsEmpty = true;
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]);
$unknownCategoryIsEmpty = false;
}
}
}
// Check if unkown category is needed
if ($unknownCategoryIsEmpty || (count($sortedCategories) == 1)){
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);
}
}
?>