Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
2028 lines (1619 sloc) 53.5 KB
<?php
// PLEASE DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
/**
* OpenID-LDAP-PHP
* An open source PHP-based OpenID IdP package using LDAP as backend.
*
* By Zdravko Stoychev <zdravko (at) 5group (dot) com> aka Dako.
* Copyright 1996-2011 by 5Group & Co. http://www.5group.com/
* See LICENSE file for more details.
*/
/**
* Set a constant to indicate that phpMyID is running
*/
define('PHPMYID_STARTED', true);
/**
* List the known types and modes
* @name $known
* @global array $GLOBALS['known']
*/
$GLOBALS['known'] = array(
'assoc_types' => array('HMAC-SHA1'),
'openid_modes' => array('accept',
'associate',
'authorize',
'cancel',
'checkid_immediate',
'checkid_setup',
'check_authentication',
'error',
'id_res',
'login',
'logout',
'sendsreg',
'sb_status',
'sb_config',
'test'),
'session_types' => array('',
'DH-SHA1'),
'bigmath_types' => array('DH-SHA1'),
);
/**
* Defined by OpenID spec
* @name $g
* @global integer $GLOBALS['g']
*/
$GLOBALS['g'] = 2;
/**
* Defined by OpenID spec
* @name $p
* @global integer $GLOBALS['p']
*/
$GLOBALS['p'] = '155172898181473697471232257763715539915724801966915404479707' .
'7953140576293785419175806512274236981889937278161526466314385615958256881888' .
'8995127215884267541995034125870655654980358010487053768147672651325574704076' .
'5857479291291572334510643245094715007229621094194349783925984760375594985848' .
'253359305585439638443';
// Runmode functions
/**
* Allow the user to accept trust on a URL
* @global array $profile
*/
function accept_mode () {
global $profile;
// this is a user session
user_session();
// the user needs refresh urls in their session to access this mode
if (! isset($_SESSION['post_accept_url']) || ! isset($_SESSION['cancel_accept_url']) || ! isset($_SESSION['unaccepted_url']))
error_500('You may not access this mode directly.');
// has the user accepted the trust_root?
$accepted = @strlen($_REQUEST['accepted'])
? $_REQUEST['accepted']
: null;
// if so, refresh back to post_accept_url
if ($accepted === 'yes') {
$_SESSION['accepted_url'] = $_SESSION['unaccepted_url'];
wrap_refresh($_SESSION['post_accept_url']);
// if they rejected it, return to the client
} elseif ($accepted === 'no') {
wrap_refresh($_SESSION['cancel_accept_url']);
}
// if neither, offer the trust request
$yes = wrap_param($profile['req_url'],'accepted=yes');
$no = wrap_param($profile['req_url'],'accepted=no');
wrap_html('The client site you are attempting to log into has requested that you trust the following URL:<br/><b>' . $_SESSION['unaccepted_url'] . '</b><br/><br/>Do you wish to continue?<br/><a href="' . $yes . '">Yes</a> | <a href="' . $no . '">No</a>');
}
/**
* Allow the user to accept sending of a SREG
* @global array $profile
*/
function sendsreg_mode () {
global $profile, $sreg;
// this is a user session
user_session();
// the user needs refresh urls in their session to access this mode
if (! isset($_SESSION['post_accept_url']) || ! isset($_SESSION['cancel_accept_url']) || ! isset($_SESSION['unaccepted_sreg']))
error_500('You may not access this mode directly.');
// has the user accepted the trust_root?
$accepted = @strlen($_REQUEST['allowed'])
? $_REQUEST['allowed']
: null;
// if so, refresh back to post_accept_url
if ($accepted === 'yes') {
$_SESSION['accepted_sreg'] = $_SESSION['unaccepted_sreg'];
wrap_refresh($_SESSION['post_accept_url']);
// if they rejected it, return to the client
} elseif ($accepted === 'no') {
wrap_refresh($_SESSION['cancel_accept_url']);
}
// if neither, offer the trust request
$yes = wrap_param($profile['req_url'],'allowed=yes');
$no = wrap_param($profile['req_url'],'allowed=no');
$sregs = $_SESSION['unaccepted_sreg'];
// Add the sreg stuff, if we've got it
$tokens = '';
foreach (explode(',', $sregs) as $key) {
if (! isset($sreg[$key]))
continue;
$tokens .= sprintf("<tr><td>%s:</td><td>%s</td></tr>", $key, $sreg[$key]);
}
if ($tokens != "")
$tokens = sprintf('<table bgcolor=#E9E8E7><tr><td colspan="2" align="center"><font color="green">Registration info details</font></td></tr>%s</table>',$tokens);
wrap_html('The client site you just have logged into has requested that you provide a registration info:<br/><b>' . $_SESSION['unaccepted_url'] . '</b><br/>' . $tokens . '<br/>Do you allow the transfer?<br/><a href="' . $yes . '">Yes</a> | <a href="' . $no . '">No</a>');
}
/**
* Produce SeatBelt Login State XML if they are logged in or not
* @global array $profile
*/
function sb_status_mode () {
global $profile;
user_session();
if ($profile['authorized']) {
// output XML with active username
wrap_seatbelt_status($_SESSION['auth_username']);
} else {
// output XML as no user has logged in
wrap_seatbelt_status();
}
}
/**
* Return SeatBelt configuration XML
* @global array $profile
*/
function sb_config_mode () {
wrap_seatbelt_config();
}
/**
* Perform an association with a consumer
* @global array $known
* @global array $profile
* @global integer $g
* @global integer $p
*/
function associate_mode () {
global $g, $known, $p, $profile;
// Validate the request
if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'associate')
error_400();
// Get the request options, using defaults as necessary
$assoc_type = (@strlen($_REQUEST['openid_assoc_type'])
&& in_array($_REQUEST['openid_assoc_type'], $known['assoc_types']))
? $_REQUEST['openid_assoc_type']
: 'HMAC-SHA1';
$session_type = (@strlen($_REQUEST['openid_session_type'])
&& in_array($_REQUEST['openid_session_type'], $known['session_types']))
? $_REQUEST['openid_session_type']
: '';
$dh_modulus = (@strlen($_REQUEST['openid_dh_modulus']))
? long(base64_decode($_REQUEST['openid_dh_modulus']))
: ($session_type == 'DH-SHA1'
? $p
: null);
$dh_gen = (@strlen($_REQUEST['openid_dh_gen']))
? long(base64_decode($_REQUEST['openid_dh_gen']))
: ($session_type == 'DH-SHA1'
? $g
: null);
$dh_consumer_public = (@strlen($_REQUEST['openid_dh_consumer_public']))
? $_REQUEST['openid_dh_consumer_public']
: ($session_type == 'DH-SHA1'
? error_post('dh_consumer_public was not specified')
: null);
$lifetime = time() + $profile['lifetime'];
// Create standard keys
$keys = array(
'assoc_type' => $assoc_type,
'expires_in' => $profile['lifetime']
);
// If I can't handle bigmath, default to plaintext sessions
if (in_array($session_type, $known['bigmath_types']) && $profile['use_bigmath'] == false)
$session_type = null;
// Add response keys based on the session type
switch ($session_type) {
case 'DH-SHA1':
// Create the associate id and shared secret now
list ($assoc_handle, $shared_secret) = new_assoc($lifetime);
// Compute the Diffie-Hellman stuff
$private_key = random($dh_modulus);
$public_key = bmpowmod($dh_gen, $private_key, $dh_modulus);
$remote_key = long(base64_decode($dh_consumer_public));
$ss = bmpowmod($remote_key, $private_key, $dh_modulus);
$keys['assoc_handle'] = $assoc_handle;
$keys['session_type'] = $session_type;
$keys['dh_server_public'] = base64_encode(bin($public_key));
$keys['enc_mac_key'] = base64_encode(x_or(sha1_20(bin($ss)), $shared_secret));
break;
default:
// Create the associate id and shared secret now
list ($assoc_handle, $shared_secret) = new_assoc($lifetime);
$keys['assoc_handle'] = $assoc_handle;
$keys['mac_key'] = base64_encode($shared_secret);
}
// Return the keys
wrap_kv($keys);
}
/**
* Perform a user authorization
* @global array $profile
*/
function authorize_mode () {
global $profile, $proto;
// this is a user session
user_session();
// the user needs refresh urls in their session to access this mode
if (! isset($_SESSION['post_auth_url']) || ! isset($_SESSION['cancel_auth_url']))
error_500('You may not access this mode directly.');
if (! $profile['user_found']) {
$c = wrap_param($_SESSION['cancel_auth_url'],'openid.mode=cancel');
wrap_html('This user does not exists! | <a href="' . $c . '">Cancel</a>');
}
// try to get the auth headers
if (function_exists('apache_request_headers') && ini_get('safe_mode') == false) {
$arh = apache_request_headers();
$hdr = isset($arh['Authorization']) ? $arh['Authorization'] : null;
} elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) {
$hdr = $_SERVER['PHP_AUTH_DIGEST'];
} elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$hdr = $_SERVER['HTTP_AUTHORIZATION'];
} elseif (isset($_ENV['PHP_AUTH_DIGEST'])) {
$hdr = $_ENV['PHP_AUTH_DIGEST'];
} elseif (isset($_SERVER['Authorization'])) {
$hdr = $_SERVER['Authorization'];
} elseif (isset($_REQUEST['auth'])) {
$hdr = stripslashes(urldecode($_REQUEST['auth']));
} else {
$hdr = null;
}
debug('Authorization header: ' . $hdr);
$myauth = substr($hdr,0,6) == 'Basic '
? substr($hdr, strpos($hdr, ' ') + 1)
: $hdr;
// is the user trying to log in?
if ($proto == "https" && ! is_null($myauth) && $profile['authorized'] == false) {
debug('Basic headers: ' . $myauth);
$hdr = array();
// decode the Basic authorization headers
// base64-encoded concatenation of the username, a colon, and the password
$myauth = base64_decode($myauth);
$hdr['username'] = substr($myauth, 0, strpos($myauth, ':'));
$hdr['password'] = substr($myauth, strpos($myauth, ':') + 1);
if ( isset($_SERVER["REMOTE_ADDR"]) ) {
$hdr['clientip'] = $_SERVER["REMOTE_ADDR"];
} elseif ( isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ) {
$hdr['clientip'] = $_SERVER["HTTP_X_FORWARDED_FOR"];
} elseif ( isset($_SERVER["HTTP_CLIENT_IP"]) ) {
$hdr['clientip'] = $_SERVER["HTTP_CLIENT_IP"];
}
debug($hdr, 'Parsed basic auth headers:');
if (! isset($_SESSION['failures']))
$_SESSION['failures'] = 0;
if (($profile['auth_username'] == $hdr['username']) && ($hdr['password'] != '')) {
$ok = test_ldap($profile['auth_cn'],$hdr['password']);
if ($ok == "ok") {
$hdr['response'] = $ok;
debug('Ldap bind is OK');
} else {
$hdr['response'] = "failed";
debug('Ldap bind FAILED');
}
// successful login!
if ($hdr['response'] == $ok) {
debug('Authentication successful for ' . $hdr['username']);
debug('User session is: ' . session_id());
$_SESSION['auth_username'] = $profile['auth_username'];
$_SESSION['auth_url'] = $profile['idp_url'];
$profile['authorized'] = true;
// return to the refresh url if they get in
wrap_refresh($_SESSION['post_auth_url']);
authlog('Login passed for ' . $hdr['username'] . ' at ' . $hdr['clientip']);
// failed login
} else {
$_SESSION['failures']++;
debug('Login failed for ' . $hdr['username']);
debug('Fail count: ' . $_SESSION['failures']);
authlog('Login FAILED for ' . $hdr['username'] . ' at ' . $hdr['clientip']);
}
} elseif ($profile['auth_username'] == $hdr['username']) {
$_SESSION['failures']++;
debug('Empty password for ' . $hdr['username']);
debug('Fail count: ' . $_SESSION['failures']);
authlog('Login FAILED for ' . $hdr['username'] . ' at ' . $hdr['clientip']);
} else {
$_SESSION['failures']++;
debug('Bad username: ' . $hdr['username']);
debug('Fail count: ' . $_SESSION['failures']);
authlog('Login FAILED for ' . $hdr['username'] . ' at ' . $hdr['clientip']);
}
// does this make too many failures?
if ($_SESSION['failures'] > 4) {
debug('Too many password failures');
error_get($_SESSION['cancel_auth_url'], 'Too many password failures. Double check your authorization realm. You must restart your browser to try again.');
}
} elseif ($proto == "http") {
error_500('You have to use secure connection (https) in order to login.');
}
// if we get this far the user is not authorized, so send the headers
debug('Prompting user to log in.');
header('HTTP/1.0 401 Unauthorized');
header(sprintf('WWW-Authenticate: Basic realm="%s"', $profile['auth_realm']));
wrap_refresh(wrap_param($_SESSION['cancel_auth_url'],'openid.mode=cancel'));
}
/**
* Handle a consumer's request for cancellation.
*/
function cancel_mode () {
wrap_html('Request cancelled.');
}
/**
* Handle a consumer's request to see if the user is authenticated
*/
function check_authentication_mode () {
// Validate the request
if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'check_authentication')
error_400();
$assoc_handle = @strlen($_REQUEST['openid_assoc_handle'])
? $_REQUEST['openid_assoc_handle']
: error_post('Missing assoc_handle');
$sig = @strlen($_REQUEST['openid_sig'])
? $_REQUEST['openid_sig']
: error_post('Missing sig');
$signed = @strlen($_REQUEST['openid_signed'])
? $_REQUEST['openid_signed']
: error_post('Missing signed');
// Prepare the return keys
$keys = array(
'openid.mode' => 'id_res'
);
// Invalidate the assoc handle if we need to
if (@strlen($_REQUEST['openid_invalidate_handle'])) {
destroy_assoc_handle($_REQUEST['openid_invalidate_handle']);
$keys['invalidate_handle'] = $_REQUEST['openid_invalidate_handle'];
}
// Validate the sig by recreating the kv pair and signing
$_REQUEST['openid_mode'] = 'id_res';
$tokens = '';
foreach (explode(',', $signed) as $param) {
$post = preg_replace('/\./', '_', $param);
$tokens .= sprintf("%s:%s\n", $param, $_REQUEST['openid_' . $post]);
}
// Add the sreg stuff, if we've got it
if (isset($sreg_required)) {
foreach (explode(',', $sreg_required) as $key) {
if (! isset($sreg[$key]))
continue;
$skey = 'sreg.' . $key;
$tokens .= sprintf("%s:%s\n", $skey, $sreg[$key]);
$keys[$skey] = $sreg[$key];
$fields[] = $skey;
}
}
// Look up the consumer's shared_secret and timeout
list ($shared_secret, $expires) = secret($assoc_handle);
// if I can't verify the assoc_handle, or if it's expired
if ($shared_secret == false || (is_numeric($expires) && $expires < time())) {
$keys['is_valid'] = 'false';
} else {
$ok = base64_encode(hmac($shared_secret, $tokens));
$keys['is_valid'] = ($sig == $ok) ? 'true' : 'false';
}
// Return the keys
wrap_kv($keys);
}
/**
* Handle a consumer's request to see if the end user is logged in
* @global array $known
* @global array $profile
* @global array $sreg
*/
function checkid ( $wait ) {
debug("checkid: wait? $wait");
global $known, $profile, $sreg;
// This is a user session
user_session();
// Get the options, use defaults as necessary
$return_to = @strlen($_REQUEST['openid_return_to'])
? $_REQUEST['openid_return_to']
: error_400('Missing return_to');
$identity = @strlen($_REQUEST['openid_identity'])
? $_REQUEST['openid_identity']
: error_get($return_to, 'Missing identity');
$assoc_handle = @strlen($_REQUEST['openid_assoc_handle'])
? $_REQUEST['openid_assoc_handle']
: null;
$trust_root = @strlen($_REQUEST['openid_trust_root'])
? $_REQUEST['openid_trust_root']
: $return_to;
$sreg_required = @strlen($_REQUEST['openid_sreg_required'])
? $_REQUEST['openid_sreg_required']
: '';
$sreg_optional = @strlen($_REQUEST['openid_sreg_optional'])
? $_REQUEST['openid_sreg_optional']
: '';
// determine the cancel url
$cancel_url = wrap_param($return_to,'openid.mode=cancel');
// required and optional make no difference to us
$sreg_required .= ',' . $sreg_optional;
// do the trust_root analysis
if ($trust_root != $return_to) {
// the urls are not the same, be sure return decends from trust
if (! url_descends($return_to, $trust_root))
error_500('Invalid trust_root: "' . $trust_root . '"');
}
// transfer the user to the url accept mode if they're paranoid
if ($wait == 1 && isset($profile['paranoid']) && $profile['paranoid'] == true && (! isset($_SESSION['accepted_url']) || $_SESSION['accepted_url'] != $trust_root)) {
$_SESSION['cancel_accept_url'] = $cancel_url;
$_SESSION['post_accept_url'] = $profile['req_url'];
$_SESSION['unaccepted_url'] = $trust_root;
debug('Transferring to acceptance mode.');
debug('Cancel URL: ' . $_SESSION['cancel_accept_url']);
debug('Post URL: ' . $_SESSION['post_accept_url']);
wrap_refresh(wrap_param($profile['idp_url'],'openid.mode=accept'));
}
$requested_identity = $identity;
// make sure i am this identifier
if ($identity != $profile['idp_url']) {
// If mismatch is only in protocol, ignore
if ($profile['smart_ssl'] && substr($identity, strpos($identity, ':') + 1) ==
substr($profile['idp_url'], strpos($profile['idp_url'], ':') + 1)) {
$identity = $profile['idp_url'];
} else {
debug("Invalid identity: $identity");
debug("IdP URL: " . $profile['idp_url']);
error_get($return_to, "Invalid identity: '$identity' expected {$profile['idp_url']}");
}
}
// begin setting up return keys
$keys = array(
'mode' => 'id_res'
);
// if the user is not logged in, transfer to the authorization mode
if ($profile['authorized'] == false || $identity != $_SESSION['auth_url']) {
// users can only be logged in to one url at a time
$_SESSION['auth_username'] = null;
$_SESSION['auth_url'] = null;
if ($wait) {
$_SESSION['cancel_auth_url'] = $cancel_url;
$_SESSION['post_auth_url'] = $profile['req_url'];
debug('Transferring to authorization mode.');
debug('Cancel URL: ' . $_SESSION['cancel_auth_url']);
debug('Post URL: ' . $_SESSION['post_auth_url']);
wrap_refresh(wrap_param($profile['idp_url'],'openid.mode=authorize'));
} else {
$keys['user_setup_url'] = $profile['idp_url'];
}
// the user is logged in
} else {
// transfer the user to the sreg accept mode if they're paranoid
if ($profile['paranoid'] == true && $sreg_required != "," && (! isset($_SESSION['accepted_sreg']) || $_SESSION['accepted_sreg'] != $sreg_required)) {
$_SESSION['cancel_accept_url'] = wrap_param($return_to,'openid.mode=cancel');
$_SESSION['post_accept_url'] = $profile['req_url'];
$_SESSION['unaccepted_sreg'] = $sreg_required;
debug('Transferring to sreg acceptance mode.');
debug('Cancel URL: ' . $_SESSION['cancel_accept_url']);
debug('Post URL: ' . $_SESSION['post_accept_url']);
debug('SREG fields: ' . $_SESSION['unaccepted_sreg']);
wrap_refresh(wrap_param($profile['idp_url'],'openid.mode=sendsreg'));
}
// remove the refresh URLs if set
unset($_SESSION['cancel_auth_url']);
unset($_SESSION['post_auth_url']);
// check the assoc handle
list($shared_secret, $expires) = secret($assoc_handle);
// if I can't verify the assoc_handle, or if it's expired
if ($shared_secret == false || (is_numeric($expires) && $expires < time())) {
debug("Session expired or missing key: $expires < " . time());
if ($assoc_handle != null) {
$keys['invalidate_handle'] = $assoc_handle;
destroy_assoc_handle($assoc_handle);
}
$lifetime = time() + $profile['lifetime'];
list ($assoc_handle, $shared_secret) = new_assoc($lifetime);
}
$keys['identity'] = $requested_identity;
$keys['assoc_handle'] = $assoc_handle;
$keys['return_to'] = $return_to;
$fields = array_keys($keys);
$tokens = '';
foreach ($fields as $key)
$tokens .= sprintf("%s:%s\n", $key, $keys[$key]);
// add sreg keys
foreach (explode(',', $sreg_required) as $key) {
if (! isset($sreg[$key]))
continue;
$skey = 'sreg.' . $key;
$tokens .= sprintf("%s:%s\n", $skey, $sreg[$key]);
$keys[$skey] = $sreg[$key];
$fields[] = $skey;
}
$keys['signed'] = implode(',', $fields);
$keys['sig'] = base64_encode(hmac($shared_secret, $tokens));
}
wrap_location($return_to, $keys);
}
/**
* Handle a consumer's request to see if the user is already logged in
*/
function checkid_immediate_mode () {
if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'checkid_immediate')
error_500();
checkid(false);
}
/**
* Handle a consumer's request to see if the user is logged in, but be willing
* to wait for them to perform a login if they're not
*/
function checkid_setup_mode () {
if (! isset($_REQUEST['openid_mode']) || $_REQUEST['openid_mode'] != 'checkid_setup')
error_500();
checkid(true);
}
/**
* Handle errors
*/
function error_mode () {
isset($_REQUEST['openid_error'])
? wrap_html($_REQUEST['openid_error'])
: error_500();
}
/**
* Show a user if they are logged in or not
* @global array $profile
*/
function id_res_mode () {
global $profile;
user_session();
if ($profile['authorized'])
wrap_html('You are logged in as <b>' . $_SESSION['auth_username'] . '</b> | <a href="' . $profile['idp_url'] . '">Continue</a>');
wrap_html('You are not logged in | <a href="' . wrap_param($profile['idp_url'],'openid.mode=login') . '">Login</a>');
}
/**
* Allow a user to perform a static login
* @global array $profile
*/
function login_mode () {
global $profile;
user_session();
if ($profile['authorized'])
id_res_mode();
$keys = array(
'mode' => 'checkid_setup',
'identity' => $profile['idp_url'],
'return_to' => $profile['idp_url']
);
wrap_location($profile['idp_url'], $keys);
}
/**
* Allow a user to perform a static logout
* @global array $profile
*/
function logout_mode () {
global $profile;
user_session();
if (! $profile['authorized'])
wrap_html('You were not logged in');
$_SESSION = array();
session_destroy();
debug('User session destroyed.');
header('HTTP/1.0 401 Unauthorized');
wrap_refresh($profile['idp_url']);
}
/**
* The default information screen
* @global array $profile
*/
function no_mode () {
global $profile, $sreg, $proto, $html, $reldir;
user_session(false);
$demo_name = $proto . '://' . $_SERVER['SERVER_NAME'] . $reldir . 'joe';
$user_name = ($sreg['fullname'] == '') ? $sreg['nickname'] : $sreg['fullname'];
$stat_html = ($profile['authorized'] == true ? ' (<font color="#FB6000">logged in</font>)' : null);
$auth_html = ($profile['authorized'] == false ? ' | <a href="' . wrap_param($profile['idp_url'],'openid.mode=login') . '">Login</a>' : null);
$test_html = ($profile['allow_test'] == true ? ' | <a href="' . wrap_param($profile['idp_url'],'openid.mode=test') . '">Test</a>' : null);
$menu_html = '<a href="' . $proto . '://' . $_SERVER['SERVER_NAME'] . $reldir . '">Home</a>' . $auth_html . $test_html . ' | <a href="http://openid.net/what/">Help</a>';
$name_html = ($profile['user_found'] == true ? 'Welcome, <font color="green">' . $user_name . '</font>! Your OpenID is:<br/><img src="images/openid.gif" border="0" align="top"> <b>' . $profile['idp_url'] . '</b>' . $stat_html . '<br/><br/>Your current options are: ' . $menu_html : '<font color="red">' . sprintf($html['user_not_found'],$profile['auth_username']) . '</font>');
$sign_html = ($profile['auth_username'] != "" ? $name_html : 'Realm: <b>' . $profile['auth_realm'] . '</b><br/><br/>' . sprintf($html['welcome_text'],$demo_name) . '<br/><br/>' . $html['welcome_help']);
wrap_html($sign_html);
}
/**
* Testing for setup
* @global array $profile
*/
function test_mode () {
global $profile, $p, $g;
if ($profile['allow_test'] != true)
error_403();
@ini_set('max_execution_time', 180);
$test_expire = time() + 120;
$test_ss_enc = 'W7hvmld2yEYdDb0fHfSkKhQX+PM=';
$test_ss = base64_decode($test_ss_enc);
$test_token = "alpha:bravo\ncharlie:delta\necho:foxtrot";
$test_server_private = '11263846781670293092494395517924811173145217135753406847875706165886322533899689335716152496005807017390233667003995430954419468996805220211293016296351031812246187748601293733816011832462964410766956326501185504714561648498549481477143603650090931135412673422192550825523386522507656442905243832471167330268';
$test_client_public = base64_decode('AL63zqI5a5p8HdXZF5hFu8p+P9GOb816HcHuvNOhqrgkKdA3fO4XEzmldlb37nv3+xqMBgWj6gxT7vfuFerEZLBvuWyVvR7IOGZmx0BAByoq3fxYd3Fpe2Coxngs015vK37otmH8e83YyyGo5Qua/NAf13yz1PVuJ5Ctk7E+YdVc');
$res = array();
// bcmath
$res['bcmath'] = extension_loaded('bcmath')
? 'pass' : 'warn - not loaded';
// gmp
if ($profile['allow_gmp']) {
$res['gmp'] = extension_loaded('gmp')
? 'pass' : 'warn - not loaded';
} else {
$res['gmp'] = 'pass - n/a';
}
// sys_get_temp_dir
$res['logfile'] = is_writable($profile['logfile'])
? 'pass' : "warn - log is not writable";
// session & new_assoc
user_session();
list($test_assoc, $test_new_ss) = new_assoc($test_expire);
$res['session'] = ($test_assoc != session_id())
? 'pass' : 'fail';
// secret
unset($_SESSION['shared_secret']);
list($check, $check2) = secret($test_assoc);
$res['secret'] = ($check == $test_new_ss)
? 'pass' : 'fail';
// expire
$res['expire'] = ($check2 <= $test_expire)
? 'pass' : 'fail';
// base64
$res['base64'] = (base64_encode($test_ss) == $test_ss_enc)
? 'pass' : 'fail';
// hmac
$test_sig = base64_decode('/VXgHvZAOdoz/OTa5+XJXzSGhjs=');
$check = hmac($test_ss, $test_token);
$res['hmac'] = ($check == $test_sig)
? 'pass' : sprintf("fail - '%s'", base64_encode($check));
if ($profile['use_bigmath']) {
// bigmath powmod
$test_server_public = '102773334773637418574009974502372885384288396853657336911033649141556441102566075470916498748591002884433213640712303846640842555822818660704173387461364443541327856226098159843042567251113889701110175072389560896826887426539315893475252988846151505416694218615764823146765717947374855806613410142231092856731';
$check = bmpowmod($g, $test_server_private, $p);
$res['bmpowmod-1'] = ($check == $test_server_public)
? 'pass' : sprintf("fail - '%s'", $check);
// long
$test_client_long = '133926731803116519408547886573524294471756220428015419404483437186057383311250738749035616354107518232016420809434801736658109316293127101479053449990587221774635063166689561125137927607200322073086097478667514042144489248048756916881344442393090205172004842481037581607299263456852036730858519133859409417564';
$res['long'] = (long($test_client_public) == $test_client_long)
? 'pass' : 'fail';
// bigmath powmod 2
$test_client_share = '19333275433742428703546496981182797556056709274486796259858099992516081822015362253491867310832140733686713353304595602619444380387600756677924791671971324290032515367930532292542300647858206600215875069588627551090223949962823532134061941805446571307168890255137575975911397744471376862555181588554632928402';
$check = bmpowmod($test_client_long, $test_server_private, $p);
$res['bmpowmod-2'] = ($check == $test_client_share)
? 'pass' : sprintf("fail - '%s'", $check);
// bin
$test_client_mac_s1 = base64_decode('G4gQQkYM6QmAzhKbVKSBahFesPL0nL3F2MREVwEtnVRRYI0ifl9zmPklwTcvURt3QTiGBd+9Dn3ESLk5qka6IO5xnILcIoBT8nnGVPiOZvTygfuzKp4tQ2mXuIATJoa7oXRGmBWtlSdFapH5Zt6NJj4B83XF/jzZiRwdYuK4HJI=');
$check = bin($test_client_share);
$res['bin'] = ($check == $test_client_mac_s1)
? 'pass' : sprintf("fail - '%s'", base64_encode($check));
} else {
$res['bigmath'] = 'fail - big math functions are not available.';
}
// sha1_20
$test_client_mac_s1 = base64_decode('G4gQQkYM6QmAzhKbVKSBahFesPL0nL3F2MREVwEtnVRRYI0ifl9zmPklwTcvURt3QTiGBd+9Dn3ESLk5qka6IO5xnILcIoBT8nnGVPiOZvTygfuzKp4tQ2mXuIATJoa7oXRGmBWtlSdFapH5Zt6NJj4B83XF/jzZiRwdYuK4HJI=');
$test_client_mac_s2 = base64_decode('0Mb2t9d/HvAZyuhbARJPYdx3+v4=');
$check = sha1_20($test_client_mac_s1);
$res['sha1_20'] = ($check == $test_client_mac_s2)
? 'pass' : sprintf("fail - '%s'", base64_encode($check));
// x_or
$test_client_mac_s3 = base64_decode('i36ZLYAJ1rYEx1VEHObrS8hgAg0=');
$check = x_or($test_client_mac_s2, $test_ss);
$res['x_or'] = ($check == $test_client_mac_s3)
? 'pass' : sprintf("fail - '%s'", base64_encode($check));
$out = "<table border=1 cellpadding=4>\n";
foreach ($res as $test => $stat) {
$code = substr($stat, 0, 4);
$color = ($code == 'pass') ? '#9f9'
: (($code == 'warn') ? '#ff9' : '#f99');
$out .= sprintf("<tr><th>%s</th><td style='background:%s'>%s</td></tr>\n", $test, $color, $stat);
}
$out .= "</table>";
wrap_html($out);
}
// Support functions
/**
* Prefix the keys of an array with 'openid.'
* @param array $array
* @return array
*/
function append_openid ($array) {
$keys = array_keys($array);
$vals = array_values($array);
$r = array();
for ($i=0; $i<sizeof($keys); $i++)
$r['openid.' . $keys[$i]] = $vals[$i];
return $r;
}
/**
* Create a big math addition function
* @param string $l
* @param string $r
* @return string
* @url http://www.icosaedro.it/bigint Inspired by
*/
function bmadd($l, $r) {
if (function_exists('bcadd'))
return bcadd($l, $r);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_add($l, $r));
$l = strval($l); $r = strval($r);
$ll = strlen($l); $rl = strlen($r);
if ($ll < $rl) {
$l = str_repeat("0", $rl-$ll) . $l;
$o = $rl;
} elseif ( $ll > $rl ) {
$r = str_repeat("0", $ll-$rl) . $r;
$o = $ll;
} else {
$o = $ll;
}
$v = '';
$carry = 0;
for ($i = $o-1; $i >= 0; $i--) {
$d = (int)$l[$i] + (int)$r[$i] + $carry;
if ($d <= 9) {
$carry = 0;
} else {
$carry = 1;
$d -= 10;
}
$v = (string) $d . $v;
}
if ($carry > 0)
$v = "1" . $v;
return $v;
}
/**
* Create a big math comparison function
* @param string $l
* @param string $r
* @return string
*/
function bmcomp($l, $r) {
if (function_exists('bccomp'))
return bccomp($l, $r);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_cmp($l, $r));
$l = strval($l); $r = strval($r);
$ll = strlen($l); $lr = strlen($r);
if ($ll != $lr)
return ($ll > $lr) ? 1 : -1;
return strcmp($l, $r);
}
/**
* Create a big math division function
* @param string $l
* @param string $r
* @param int $z
* @return string
* @url http://www.icosaedro.it/bigint Inspired by
*/
function bmdiv($l, $r, $z = 0) {
if (function_exists('bcdiv'))
return ($z == 0) ? bcdiv($l, $r) : bcmod($l, $r);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(($z == 0) ? gmp_div_q($l, $r) : gmp_mod($l, $r));
$l = strval($l); $r = strval($r);
$v = '0';
while (true) {
if( bmcomp($l, $r) < 0 )
break;
$delta = strlen($l) - strlen($r);
if ($delta >= 1) {
$zeroes = str_repeat("0", $delta);
$r2 = $r . $zeroes;
if (strcmp($l, $r2) >= 0) {
$v = bmadd($v, "1" . $zeroes);
$l = bmsub($l, $r2);
} else {
$zeroes = str_repeat("0", $delta - 1);
$v = bmadd($v, "1" . $zeroes);
$l = bmsub($l, $r . $zeroes);
}
} else {
$l = bmsub($l, $r);
$v = bmadd($v, "1");
}
}
return ($z == 0) ? $v : $l;
}
/**
* Create a big math multiplication function
* @param string $l
* @param string $r
* @return string
* @url http://www.icosaedro.it/bigint Inspired by
*/
function bmmul($l, $r) {
if (function_exists('bcmul'))
return bcmul($l, $r);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_mul($l, $r));
$l = strval($l); $r = strval($r);
$v = '0';
$z = '';
for( $i = strlen($r)-1; $i >= 0; $i-- ){
$bd = (int) $r[$i];
$carry = 0;
$p = "";
for( $j = strlen($l)-1; $j >= 0; $j-- ){
$ad = (int) $l[$j];
$pd = $ad * $bd + $carry;
if( $pd <= 9 ){
$carry = 0;
} else {
$carry = (int) ($pd / 10);
$pd = $pd % 10;
}
$p = (string) $pd . $p;
}
if( $carry > 0 )
$p = (string) $carry . $p;
$p = $p . $z;
$z .= "0";
$v = bmadd($v, $p);
}
return $v;
}
/**
* Create a big math modulus function
* @param string $value
* @param string $mod
* @return string
*/
function bmmod( $value, $mod ) {
if (function_exists('bcmod'))
return bcmod($value, $mod);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_mod($value, $mod));
$r = bmdiv($value, $mod, 1);
return $r;
}
/**
* Create a big math power function
* @param string $value
* @param string $exponent
* @return string
*/
function bmpow ($value, $exponent) {
if (function_exists('bcpow'))
return bcpow($value, $exponent);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_pow($value, $exponent));
$r = '1';
while ($exponent) {
$r = bmmul($r, $value, 100);
$exponent--;
}
return (string)rtrim($r, '0.');
}
/**
* Create a big math 'powmod' function
* @param string $value
* @param string $exponent
* @param string $mod
* @return string
* @url http://php.net/manual/en/function.bcpowmod.php#72704 Borrowed from
*/
function bmpowmod ($value, $exponent, $mod) {
if (function_exists('bcpowmod'))
return bcpowmod($value, $exponent, $mod);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_powm($value, $exponent, $mod));
$r = '';
while ($exponent != '0') {
$t = bmmod($exponent, '4096');
$r = substr("000000000000" . decbin(intval($t)), -12) . $r;
$exponent = bmdiv($exponent, '4096');
}
$r = preg_replace("!^0+!","",$r);
if ($r == '')
$r = '0';
$value = bmmod($value, $mod);
$erb = strrev($r);
$q = '1';
$a[0] = $value;
for ($i = 1; $i < strlen($erb); $i++) {
$a[$i] = bmmod( bmmul($a[$i-1], $a[$i-1]), $mod );
}
for ($i = 0; $i < strlen($erb); $i++) {
if ($erb[$i] == "1") {
$q = bmmod( bmmul($q, $a[$i]), $mod );
}
}
return($q);
}
/**
* Create a big math subtraction function
* @param string $l
* @param string $r
* @return string
* @url http://www.icosaedro.it/bigint Inspired by
*/
function bmsub($l, $r) {
if (function_exists('bcsub'))
return bcsub($l, $r);
global $profile;
if ($profile['use_gmp'])
return gmp_strval(gmp_sub($l, $r));
$l = strval($l); $r = strval($r);
$ll = strlen($l); $rl = strlen($r);
if ($ll < $rl) {
$l = str_repeat("0", $rl-$ll) . $l;
$o = $rl;
} elseif ( $ll > $rl ) {
$r = str_repeat("0", $ll-$rl) . (string)$r;
$o = $ll;
} else {
$o = $ll;
}
if (strcmp($l, $r) >= 0) {
$sign = '';
} else {
$x = $l; $l = $r; $r = $x;
$sign = '-';
}
$v = '';
$carry = 0;
for ($i = $o-1; $i >= 0; $i--) {
$d = ($l[$i] - $r[$i]) - $carry;
if ($d < 0) {
$carry = 1;
$d += 10;
} else {
$carry = 0;
}
$v = (string) $d . $v;
}
return $sign . ltrim($v, '0');
}
/**
* Get a binary value
* @param integer $n
* @return string
* @url http://openidenabled.com Borrowed from PHP-OpenID
*/
function bin ($n) {
$bytes = array();
while (bmcomp($n, 0) > 0) {
array_unshift($bytes, bmmod($n, 256));
$n = bmdiv($n, bmpow(2,8));
}
if ($bytes && ($bytes[0] > 127))
array_unshift($bytes, 0);
$b = '';
foreach ($bytes as $byte)
$b .= pack('C', $byte);
return $b;
}
/**
* Debug logging
* @param mixed $x
* @param string $m
*/
function debug ($x, $m = null) {
global $profile;
if (! isset($profile['debug']) || $profile['debug'] == false)
return true;
if (! is_writable(dirname($profile['logfile'])) &! is_writable($profile['logfile']))
error_500('Cannot write to log file: ' . $profile['logfile']);
if (is_array($x)) {
ob_start();
print_r($x);
$x = $m . ($m != null ? "\n" : '') . ob_get_clean();
} else {
$x .= "\n";
}
error_log($x . "\n", 3, $profile['logfile']);
}
/**
* Auth logging
* @param string $m
*/
function authlog ($m) {
global $profile;
if (! isset($profile['authlog']) || $profile['authlog'] == false)
return true;
if (! is_writable(dirname($profile['logfile'])) &! is_writable($profile['logfile']))
error_500('Cannot write to log file: ' . $profile['logfile']);
error_log($m . "\n\n", 3, $profile['logfile']);
}
/**
* Destroy a consumer's assoc handle
* @param string $id
*/
function destroy_assoc_handle ( $id ) {
debug("Destroying session: $id");
$sid = session_id();
session_write_close();
session_id($id);
session_start();
session_destroy();
session_id($sid);
session_start();
}
/**
* Return an error message to the user
* @param string $message
*/
function error_400 ( $message = 'Bad Request' ) {
header("HTTP/1.1 400 Bad Request");
wrap_html($message);
}
/**
* Return an error message to the user
* @param string $message
*/
function error_403 ( $message = 'Forbidden' ) {
header("HTTP/1.1 403 Forbidden");
wrap_html($message);
}
/**
* Return an error message to the user
* @param string $message
*/
function error_500 ( $message = 'Internal Server Error' ) {
header("HTTP/1.1 500 Internal Server Error");
wrap_html($message);
}
/**
* Return an error message to the consumer
* @param string $message
*/
function error_get ( $url, $message = 'Bad Request') {
wrap_location($url, array('mode' => 'error', 'error' => $message));
}
/**
* Return an error message to the consumer
* @param string $message
*/
function error_post ( $message = 'Bad Request' ) {
header("HTTP/1.1 400 Bad Request");
echo ('error:' . $message);
exit(0);
}
/**
* Do an HMAC
* @param string $key
* @param string $data
* @param string $hash
* @return string
* @url http://php.net/manual/en/function.sha1.php#39492 Borrowed from
*/
function hmac($key, $data, $hash = 'sha1_20') {
$blocksize=64;
if (strlen($key) > $blocksize)
$key = $hash($key);
$key = str_pad($key, $blocksize,chr(0x00));
$ipad = str_repeat(chr(0x36),$blocksize);
$opad = str_repeat(chr(0x5c),$blocksize);
$h1 = $hash(($key ^ $ipad) . $data);
$hmac = $hash(($key ^ $opad) . $h1);
return $hmac;
}
if (! function_exists('http_build_query')) {
/**
* Create function if missing
* @param array $array
* @return string
*/
function http_build_query ($array) {
$r = array();
foreach ($array as $key => $val)
$r[] = sprintf('%s=%s', urlencode($key), urlencode($val));
return implode('&', $r);
}}
/**
* Turn a binary back into a long
* @param string $b
* @return integer
* @url http://openidenabled.com Borrowed from PHP-OpenID
*/
function long($b) {
$bytes = array_merge(unpack('C*', $b));
$n = 0;
foreach ($bytes as $byte) {
$n = bmmul($n, bmpow(2,8));
$n = bmadd($n, $byte);
}
return $n;
}
/**
* Create a new consumer association
* @param integer $expiration
* @return array
*/
function new_assoc ( $expiration ) {
if (isset($_SESSION) && is_array($_SESSION)) {
$sid = session_id();
$dat = session_encode();
session_write_close();
}
session_start();
session_regenerate_id('false');
$id = session_id();
$shared_secret = new_secret();
debug('Started new assoc session: ' . $id);
$_SESSION = array();
$_SESSION['expiration'] = $expiration;
$_SESSION['shared_secret'] = base64_encode($shared_secret);
session_write_close();
if (isset($sid)) {
session_id($sid);
session_start();
$_SESSION = array();
session_decode($dat);
}
return array($id, $shared_secret);
}
/**
* Create a new shared secret
* @return string
*/
function new_secret () {
$r = '';
for($i=0; $i<20; $i++)
$r .= chr(mt_rand(0, 255));
debug("Generated new key: hash = '" . md5($r) . "', length = '" . strlen($r) . "'");
return $r;
}
/**
* Random number generation
* @param integer max
* @return integer
*/
function random ( $max ) {
if (strlen($max) < 4)
return mt_rand(1, $max - 1);
$r = '';
for($i=1; $i<strlen($max) - 1; $i++)
$r .= mt_rand(0,9);
$r .= mt_rand(1,9);
return $r;
}
/**
* Get the shared secret and expiration time for the specified assoc_handle
* @param string $handle assoc_handle to look up
* @return array (shared_secret, expiration_time)
*/
function secret ( $handle ) {
if (! preg_match('/^\w+$/', $handle))
return array(false, 0);
if (isset($_SESSION) && is_array($_SESSION)) {
$sid = session_id();
$dat = session_encode();
session_write_close();
}
session_id($handle);
session_start();
debug('Started session to acquire key: ' . session_id());
$secret = isset($_SESSION['shared_secret'])
? base64_decode($_SESSION['shared_secret'])
: false;
$expiration = isset($_SESSION['expiration'])
? $_SESSION['expiration']
: null;
session_write_close();
if (isset($sid)) {
session_id($sid);
session_start();
$_SESSION = array();
session_decode($dat);
}
debug("Found key: hash = '" . md5($secret) . "', length = '" . strlen($secret) . "', expiration = '$expiration'");
return array($secret, $expiration);
}
/**
* Do an internal self check
* @global array $profile
* @global array $sreg
*/
function self_check () {
global $profile, $sreg;
if (! isset($profile) || ! is_array($profile))
error_500('No configuration found, you shouldn\'t access this file directly.');
if (version_compare(phpversion(), '4.2.0', 'lt'))
error_500('The required minimum version of PHP is 4.2.0, you are running ' . phpversion());
$extension_r = array('session', 'pcre');
foreach ($extension_r as $x) {
if (! extension_loaded($x))
@dl($x);
if (! extension_loaded($x))
error_500("Required extension '$x' is missing.");
}
$extension_b = array('suhosin');
foreach ($extension_b as $x) {
if (extension_loaded($x))
error_500("This site is not compatible with '$x'");
}
$keys = array('auth_username');
foreach ($keys as $key) {
if (! array_key_exists($key, $profile))
error_500("'$key' is missing from your profile.");
}
if (! isset($sreg) || ! is_array($sreg))
$sreg = array();
}
/**
* Do SHA1 20 byte encryption
* @param string $v
* @return string
* @url http://openidenabled.com Borrowed from PHP-OpenID
*/
function sha1_20 ($v) {
if (version_compare(phpversion(), '5.0.0', 'ge'))
return sha1($v, true);
$hex = sha1($v);
$r = '';
for ($i = 0; $i < 40; $i += 2) {
$hexcode = substr($hex, $i, 2);
$charcode = base_convert($hexcode, 16, 10);
$r .= chr($charcode);
}
return $r;
}
/**
* Look for the point of differentiation in two strings
* @param string $a
* @param string $b
* @return int
*/
function str_diff_at ($a, $b) {
if ($a == $b)
return -1;
$n = min(strlen($a), strlen($b));
for ($i = 0; $i < $n; $i++)
if ($a[$i] != $b[$i])
return $i;
return $n;
}
if (! function_exists('sys_get_temp_dir') && ini_get('open_basedir') == false) {
/**
* Create function if missing
* @return string
*/
function sys_get_temp_dir () {
$keys = array('TMP', 'TMPDIR', 'TEMP');
foreach ($keys as $key) {
if (isset($_ENV[$key]) && is_dir($_ENV[$key]) && is_writable($_ENV[$key]))
return realpath($_ENV[$key]);
}
$tmp = tempnam(false, null);
if (file_exists($tmp)) {
$dir = realpath(dirname($tmp));
unlink($tmp);
return realpath($dir);
}
return realpath(dirname(__FILE__));
}} elseif (! function_exists('sys_get_temp_dir')) {
function sys_get_temp_dir () {
return realpath(dirname(__FILE__));
}}
/**
* Determine if a child URL actually decends from the parent, and that the
* parent is a good URL.
* THIS IS EXPERIMENTAL
* @param string $parent
* @param string $child
* @return bool
*/
function url_descends ( $child, $parent ) {
if ($child == $parent)
return true;
$keys = array();
$parts = array();
$req = array('scheme', 'host');
$bad = array('fragment', 'pass', 'user');
foreach (array('parent', 'child') as $name) {
$parts[$name] = @parse_url($$name);
if ($parts[$name] == false)
return false;
$keys[$name] = array_keys($parts[$name]);
if (array_intersect($keys[$name], $req) != $req)
return false;
if (array_intersect($keys[$name], $bad) != array())
return false;
if (! preg_match('/^https?$/i', strtolower($parts[$name]['scheme'])))
return false;
if (! array_key_exists('port', $parts[$name]))
$parts[$name]['port'] = (strtolower($parts[$name]['scheme']) == 'https') ? 443 : 80;
if (! array_key_exists('path', $parts[$name]))
$parts[$name]['path'] = '/';
}
// port and scheme must match
if ($parts['parent']['scheme'] != $parts['child']['scheme'] ||
$parts['parent']['port'] != $parts['child']['port'])
return false;
// compare the hosts by reversing the strings
$cr_host = strtolower(strrev($parts['child']['host']));
$pr_host = strtolower(strrev($parts['parent']['host']));
$break = str_diff_at($cr_host, $pr_host);
// $dots = preg_match_all('/(\.)/', $pr_host, $chunks);
if ($break >= 0 && ($pr_host[$break] != '*' || substr_count(substr($pr_host, 0, $break), '.') < 2))
return false;
// now compare the paths
$break = str_diff_at($parts['child']['path'], $parts['parent']['path']);
if ($break >= 0
&& ($break < strlen($parts['parent']['path']) && $parts['parent']['path'][$break] != '*')
|| ($break > strlen($parts['child']['path'])))
return false;
return true;
}
/**
* Create a user session
* @global array $profile
* @global array $proto
*/
function user_session ($really_try = true) {
global $proto, $profile;
if ($profile['smart_ssl']) {
if ($really_try && !($_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off')) {
header('Location: https://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
exit();
}
session_set_cookie_params(0, '/', '', true, true);
}
session_name('OpenIDLdap_Server');
@session_start();
$profile['authorized'] = (isset($_SESSION['auth_username'])
&& $_SESSION['auth_username'] == $profile['auth_username'])
? true
: false;
debug('Started user session: ' . session_id() . ' Auth? ' . $profile['authorized']);
}
/**
* Return HTML
* @global string $charset
* @param string $message
*/
function wrap_html ($message) {
global $charset, $profile, $html;
header('Content-Type: text/html; charset=' . $charset);
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>' . $html['page_title'] . '</title>
<link rel="openid.server" href="' . $profile['req_url'] . '" />
<link rel="openid.delegate" href="' . $profile['idp_url'] . '" />
<link rel="seatbelt.config" type="application/xml" href="' . $profile['idp_url'] . '?openid.mode=sb_config" />
' . implode("\n", $profile['opt_headers']) . '
<meta name="charset" content="' . $charset . '" />
<meta name="robots" content="noindex,nofollow" />
' . $html['page_head'] . '
</head>
<body>
<p>' . $html['page_header'] . '</p>
<p>' . $message . '</p>
</body>
</html>
';
exit(0);
}
/**
* Return a key-value pair in plain text
* @global string $charset
* @param array $keys
*/
function wrap_kv ($keys) {
global $charset;
debug($keys, 'Wrapped key/vals');
header('Content-Type: text/plain; charset=' . $charset);
foreach ($keys as $key => $value)
printf("%s:%s\n", $key, $value);
exit(0);
}
/**
* Return an HTML refresh, with OpenID keys
* @param string $url
* @param array @keys
*/
function wrap_location ($url, $keys) {
$keys = append_openid($keys);
debug($keys, 'Location keys');
$c = wrap_param($url,http_build_query($keys));
header('Location: ' . $c);
debug('Location: ' . $c);
exit(0);
}
/**
* Return an HTML with new parameret added
* @param string $url
* $param string $param
*/
function wrap_param ($url, $param) {
$q = strpos($url, '?') ? '&' : '?';
return $url . $q . $param;
}
/**
* Return an HTML refresh
* @global string $charset
* @param string $url
*/
function wrap_refresh ($url) {
global $charset, $sreg, $html, $profile;
$pos = strpos($url, 'openid.mode=authorize');
if ($pos == false) {
$site = '';
} else {
$user_name = ($sreg['fullname'] == '') ? $sreg['nickname'] : $sreg['fullname'];
$party_url = ($profile['paranoid'] == true ? $_SESSION['accepted_url'] : $_SESSION['cancel_auth_url']);
$site = '<p>Hello, <font color="green">' . $user_name . '</font>! You are going to confirm your identity to a client site with URL:<br/><b>' . $party_url . '</b></p>';
}
header('Content-Type: text/html; charset=' . $charset);
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>' . $html['page_title'] . '</title>
<meta http-equiv="refresh" content="0;url=' . $url . '">
' . $html['page_head'] . '
</head>
<body>
<p>' . $html['page_header'] . '</p>' . $site . '
<p>Redirecting to <a href="' . $url . '">' . $url . '</a></p>
</body>
</html>
';
debug('Refresh: ' . $url);
exit(0);
}
/**
* Implement binary x_or
* @param string $a
* @param string $b
* @return string
*/
function x_or ($a, $b) {
$r = "";
for ($i = 0; $i < strlen($b); $i++)
$r .= $a[$i] ^ $b[$i];
debug("Xor size: " . strlen($r));
return $r;
}
/**
* Return SeatBelt state XML
* @global string $charset
* @param string $name
*/
function wrap_seatbelt_status ( $name = false ) {
global $charset, $profile;
header('Content-Type: application/xml; charset=' . $charset);
echo '<?xml version="1.0" encoding="UTF-8" ?><personaConfig version="1.0" serverIdentifier="' . $profile['idp_url'] . '">';
if ($name != false) {
echo '<persona displayName="' . $name . '">' . $profile['idp_url'] . '</persona>';
}
echo '</personaConfig>';
exit(0);
}
/**
* Return SeatBelt configuration XML file
* @global string $charset
* @global array $profile
*/
function wrap_seatbelt_config () {
global $charset, $profile, $proto, $reldir, $html;
$current_url = $proto . '://' . $_SERVER['SERVER_NAME'] . $reldir;
$out = '<?xml version="1.0" encoding="UTF-8"?>
<opConfig version="1.0" serverIdentifier="' . $profile['idp_url'] . '">
<configRevision></configRevision>
<title>' . $html['page_title'] . '</title>
<description>' . $html['seatbelt_text'] . '</description>
<loginUrl>' . $profile["idp_url"] . '?openid.mode=login</loginUrl>
<welcomeUrl>' . $profile["idp_url"] . '</welcomeUrl>
<loginStateUrl>' . $profile["idp_url"] . '?openid.mode=sb_status</loginStateUrl>
<opDomain></opDomain>
<opCertSHA1Hash></opCertSHA1Hash>
<opCertCommonName></opCertCommonName>
<settingsIconUrl>' . $current_url . 'images/seatbelt/icon-logo.png</settingsIconUrl>
<toolbarGrayIconUrl>' . $current_url . 'images/seatbelt/icon-gray.png</toolbarGrayIconUrl>
<toolbarHighIconUrl>' . $current_url . 'images/seatbelt/icon-high.png</toolbarHighIconUrl>
<toolbarGrayBackground>#D6D6D6</toolbarGrayBackground>
<toolbarHighBackground>#EEEEEE</toolbarHighBackground>
<toolbarLoginBackground>#74D174</toolbarLoginBackground>
<toolbarGrayBorder>#7C7C7C</toolbarGrayBorder>
<toolbarHighBorder>#009900</toolbarHighBorder>
<toolbarLoginBorder>#2B802B</toolbarLoginBorder>
<toolbarGrayText>#666666</toolbarGrayText>
<toolbarHighText>#009900</toolbarHighText>
<toolbarLoginText>#FFFFFF</toolbarLoginText>
</opConfig>';
header('Content-Type: application/xml; charset=' . $charset);
echo $out;
exit(0);
}
/*
* App Initialization
*/
// Determine the charset to use
$GLOBALS['charset'] = 'iso-8859-1';
// Set the internal encoding
if (function_exists('mb_internal_encoding'))
mb_internal_encoding($charset);
// Avoid problems with non-default arg_separator.output settings
// Credit for this goes to user 'prelog' on the forums
ini_set('arg_separator.output', '&');
// Do a check to be sure everything is set up correctly
self_check();
/**
* Determine the HTTP request port
* @name $port
* @global integer $GLOBALS['port']
*/
$GLOBALS['port'] = ((isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on' && $_SERVER['SERVER_PORT'] == 443)
|| ($_SERVER['SERVER_PORT'] == 80) || ($_SERVER['SERVER_PORT'] == 443)) // Omit default ports
? ''
: ':' . $_SERVER['SERVER_PORT'];
debug("Port: " . $_SERVER['SERVER_PORT'] . ' => ' . $GLOBALS['port']);
/**
* Determine the HTTP request protocol
* @name $proto
* @global string $GLOBALS['proto']
*/
$GLOBALS['proto'] = (($profile['force_ssl'] == true) || ($_SERVER['SERVER_PORT'] == 443) || (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on')) ? 'https' : 'http';
debug("Proto: " . $GLOBALS['proto']);
/**
* Determine the relative server path, i.e. where the package is installed
* @name $reldir
* @global string $GLOBALS['reldir']
*/
$GLOBALS['reldir'] = substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/') + 1);
debug("Path: " . $GLOBALS['reldir']);
// Set the authorization state - DO NOT OVERRIDE
$profile['authorized'] = false;
// Set a default log file
if (! array_key_exists('logfile', $profile))
$profile['logfile'] = '/var/log/openid';
// Set a default IDP URL
if (! array_key_exists('idp_url', $profile))
$profile['idp_url'] = sprintf("%s://%s%s%s",
$proto,
$_SERVER['SERVER_NAME'],
$port,
($profile['auth_username'] != "") ? $GLOBALS['reldir'] . $profile['auth_username'] : $_SERVER['PHP_SELF']);
// Determine the requested URL - DO NOT OVERRIDE
$profile['req_url'] = sprintf("%s://%s%s%s",
$proto,
$_SERVER['HTTP_HOST'],
$port,
$_SERVER["REQUEST_URI"]);
// Set the default allowance for testing
if (! array_key_exists('allow_test', $profile))
$profile['allow_test'] = false;
// Set the default allowance for gmp
if (! array_key_exists('allow_gmp', $profile))
$profile['allow_gmp'] = false;
// Set the default force bigmath - BAD IDEA to override this
if (! array_key_exists('force_bigmath', $profile))
$profile['force_bigmath'] = false;
// Determine if GMP is usable
$profile['use_gmp'] = (extension_loaded('gmp') && $profile['allow_gmp']) ? true : false;
// Determine if I can perform big math functions
$profile['use_bigmath'] = (extension_loaded('bcmath') || $profile['use_gmp'] || $profile['force_bigmath']) ? true : false;
// Set a default authentication domain
if (! array_key_exists('auth_domain', $profile))
$profile['auth_domain'] = $profile['req_url'] . ' ' . $profile['idp_url'];
// Set a default authentication realm
if (! array_key_exists('auth_realm', $profile))
$profile['auth_realm'] = 'OpenID';
// Determine the realm for authentication - DO NOT OVERRIDE
$profile['php_realm'] = $profile['auth_realm'] . (ini_get('safe_mode') ? '-' . getmyuid() : '');
// Set a default lifetime - the lesser of GC and cache time
if (! array_key_exists('lifetime', $profile)) {
$sce = session_cache_expire() * 60;
$gcm = ini_get('session.gc_maxlifetime');
$profile['lifetime'] = $sce < $gcm ? $sce : $gcm;
}
/*
* Optional Initialization
*/
// Setup optional headers
$profile['opt_headers'] = array();
// Determine if I should add microid stuff
if (array_key_exists('microid', $profile)) {
$hash = sha1($profile['idp_url']);
$values = is_array($profile['microid']) ? $profile['microid'] : array($profile['microid']);
foreach ($values as $microid) {
preg_match('/^([a-z]+)/i', $microid, $mtx);
$profile['opt_headers'][] = sprintf('<meta name="microid" content="%s+%s:sha1:%s" />', $mtx[1], $proto, sha1(sha1($microid) . $hash));
}
}
// Determine if I should add pavatar stuff
if (array_key_exists('pavatar', $profile))
$profile['opt_headers'][] = sprintf('<link rel="pavatar" href="%s" />', $profile['pavatar']);
/*
* Do it
*/
// Decide which runmode, based on user request or default
$run_mode = (isset($_REQUEST['openid_mode'])
&& in_array($_REQUEST['openid_mode'], $known['openid_modes']))
? $_REQUEST['openid_mode']
: 'no';
// Run in the determined runmode
debug("Run mode: $run_mode at: " . time());
debug($_REQUEST, 'Request params');
$run_mode .= '_mode';
$run_mode();