summaryrefslogtreecommitdiffstats
path: root/3rdparty
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2012-07-24 00:02:01 +0200
committerRobin Appelman <icewind@owncloud.com>2012-07-24 00:02:01 +0200
commit796768577154dc9cc2542e33d8d81c6a5fa77dea (patch)
treef9dd3a9aeb1baa8f9c65f5b8e67770c5257e4b7c /3rdparty
parent59364366d8c69ca217fb817535d1b5d1df316841 (diff)
downloadnextcloud-server-796768577154dc9cc2542e33d8d81c6a5fa77dea.tar.gz
nextcloud-server-796768577154dc9cc2542e33d8d81c6a5fa77dea.zip
move some openid files to 3rdparty
Diffstat (limited to '3rdparty')
-rw-r--r--3rdparty/openid/class.openid.v3.php326
-rw-r--r--3rdparty/openid/phpmyid.php1707
2 files changed, 2033 insertions, 0 deletions
diff --git a/3rdparty/openid/class.openid.v3.php b/3rdparty/openid/class.openid.v3.php
new file mode 100644
index 00000000000..eeb31986659
--- /dev/null
+++ b/3rdparty/openid/class.openid.v3.php
@@ -0,0 +1,326 @@
+<?php
+/*
+ FREE TO USE
+ Under License: GPLv3
+ Simple OpenID PHP Class
+
+ Some modifications by Eddie Roosenmaallen, eddie@roosenmaallen.com
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+This Class was written to make easy for you to integrate OpenID on your website.
+This is just a client, which checks for user's identity. This Class Requires CURL Module.
+It should be easy to use some other HTTP Request Method, but remember, often OpenID servers
+are using SSL.
+We need to be able to perform SSL Verification on the background to check for valid signature.
+
+HOW TO USE THIS CLASS:
+ STEP 1)
+ $openid = new SimpleOpenID;
+ :: SET IDENTITY ::
+ $openid->SetIdentity($_POST['openid_url']);
+ :: SET RETURN URL ::
+ $openid->SetApprovedURL('http://www.yoursite.com/return.php'); // Script which handles a response from OpenID Server
+ :: SET TRUST ROOT ::
+ $openid->SetTrustRoot('http://www.yoursite.com/');
+ :: FETCH SERVER URL FROM IDENTITY PAGE :: [Note: It is recomended to cache this (Session, Cookie, Database)]
+ $openid->GetOpenIDServer(); // Returns false if server is not found
+ :: REDIRECT USER TO OPEN ID SERVER FOR APPROVAL ::
+
+ :: (OPTIONAL) SET OPENID SERVER ::
+ $openid->SetOpenIDServer($server_url); // If you have cached previously this, you don't have to call GetOpenIDServer and set value this directly
+
+ STEP 2)
+ Once user gets returned we must validate signature
+ :: VALIDATE REQUEST ::
+ true|false = $openid->ValidateWithServer();
+
+ ERRORS:
+ array = $openid->GetError(); // Get latest Error code
+
+ FIELDS:
+ OpenID allowes you to retreive a profile. To set what fields you'd like to get use (accepts either string or array):
+ $openid->SetRequiredFields(array('email','fullname','dob','gender','postcode','country','language','timezone'));
+ or
+ $openid->SetOptionalFields('postcode');
+
+IMPORTANT TIPS:
+OPENID as is now, is not trust system. It is a great single-sign on method. If you want to
+store information about OpenID in your database for later use, make sure you handle url identities
+properly.
+ For example:
+ https://steve.myopenid.com/
+ https://steve.myopenid.com
+ http://steve.myopenid.com/
+ http://steve.myopenid.com
+ ... are representing one single user. Some OpenIDs can be in format openidserver.com/users/user/ - keep this in mind when storing identities
+
+ To help you store an OpenID in your DB, you can use function:
+ $openid_db_safe = $openid->OpenID_Standarize($upenid);
+ This may not be comatible with current specs, but it works in current enviroment. Use this function to get openid
+ in one format like steve.myopenid.com (without trailing slashes and http/https).
+ Use output to insert Identity to database. Don't use this for validation - it may fail.
+
+*/
+
+class SimpleOpenID{
+ var $openid_url_identity;
+ var $URLs = array();
+ var $error = array();
+ var $fields = array(
+ 'required' => array(),
+ 'optional' => array(),
+ );
+
+ function SimpleOpenID(){
+ if (!function_exists('curl_exec')) {
+ die('Error: Class SimpleOpenID requires curl extension to work');
+ }
+ }
+ function SetOpenIDServer($a){
+ $this->URLs['openid_server'] = $a;
+ }
+ function SetTrustRoot($a){
+ $this->URLs['trust_root'] = $a;
+ }
+ function SetCancelURL($a){
+ $this->URLs['cancel'] = $a;
+ }
+ function SetApprovedURL($a){
+ $this->URLs['approved'] = $a;
+ }
+ function SetRequiredFields($a){
+ if (is_array($a)){
+ $this->fields['required'] = $a;
+ }else{
+ $this->fields['required'][] = $a;
+ }
+ }
+ function SetOptionalFields($a){
+ if (is_array($a)){
+ $this->fields['optional'] = $a;
+ }else{
+ $this->fields['optional'][] = $a;
+ }
+ }
+ function SetIdentity($a){ // Set Identity URL
+ if ((stripos($a, 'http://') === false)
+ && (stripos($a, 'https://') === false)){
+ $a = 'http://'.$a;
+ }
+/*
+ $u = parse_url(trim($a));
+ if (!isset($u['path'])){
+ $u['path'] = '/';
+ }else if(substr($u['path'],-1,1) == '/'){
+ $u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
+ }
+ if (isset($u['query'])){ // If there is a query string, then use identity as is
+ $identity = $a;
+ }else{
+ $identity = $u['scheme'] . '://' . $u['host'] . $u['path'];
+ }
+//*/
+ $this->openid_url_identity = $a;
+ }
+ function GetIdentity(){ // Get Identity
+ return $this->openid_url_identity;
+ }
+ function GetError(){
+ $e = $this->error;
+ return array('code'=>$e[0],'description'=>$e[1]);
+ }
+
+ function ErrorStore($code, $desc = null){
+ $errs['OPENID_NOSERVERSFOUND'] = 'Cannot find OpenID Server TAG on Identity page.';
+ if ($desc == null){
+ $desc = $errs[$code];
+ }
+ $this->error = array($code,$desc);
+ }
+
+ function IsError(){
+ if (count($this->error) > 0){
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ function splitResponse($response) {
+ $r = array();
+ $response = explode("\n", $response);
+ foreach($response as $line) {
+ $line = trim($line);
+ if ($line != "") {
+ list($key, $value) = explode(":", $line, 2);
+ $r[trim($key)] = trim($value);
+ }
+ }
+ return $r;
+ }
+
+ function OpenID_Standarize($openid_identity = null){
+ if ($openid_identity === null)
+ $openid_identity = $this->openid_url_identity;
+
+ $u = parse_url(strtolower(trim($openid_identity)));
+
+ if (!isset($u['path']) || ($u['path'] == '/')) {
+ $u['path'] = '';
+ }
+ if(substr($u['path'],-1,1) == '/'){
+ $u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
+ }
+ if (isset($u['query'])){ // If there is a query string, then use identity as is
+ return $u['host'] . $u['path'] . '?' . $u['query'];
+ }else{
+ return $u['host'] . $u['path'];
+ }
+ }
+
+ function array2url($arr){ // converts associated array to URL Query String
+ if (!is_array($arr)){
+ return false;
+ }
+ $query = '';
+ foreach($arr as $key => $value){
+ $query .= $key . "=" . $value . "&";
+ }
+ return $query;
+ }
+ function FSOCK_Request($url, $method="GET", $params = ""){
+ $fp = fsockopen("ssl://www.myopenid.com", 443, $errno, $errstr, 3); // Connection timeout is 3 seconds
+ if (!$fp) {
+ $this->ErrorStore('OPENID_SOCKETERROR', $errstr);
+ return false;
+ } else {
+ $request = $method . " /server HTTP/1.0\r\n";
+ $request .= "User-Agent: Simple OpenID PHP Class (http://www.phpclasses.org/simple_openid)\r\n";
+ $request .= "Connection: close\r\n\r\n";
+ fwrite($fp, $request);
+ stream_set_timeout($fp, 4); // Connection response timeout is 4 seconds
+ $res = fread($fp, 2000);
+ $info = stream_get_meta_data($fp);
+ fclose($fp);
+
+ if ($info['timed_out']) {
+ $this->ErrorStore('OPENID_SOCKETTIMEOUT');
+ } else {
+ return $res;
+ }
+ }
+ }
+ function CURL_Request($url, $method="GET", $params = "") { // Remember, SSL MUST BE SUPPORTED
+ if (is_array($params)) $params = $this->array2url($params);
+ $curl = curl_init($url . ($method == "GET" && $params != "" ? "?" . $params : ""));
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($curl, CURLOPT_HEADER, false);
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($curl, CURLOPT_HTTPGET, ($method == "GET"));
+ curl_setopt($curl, CURLOPT_POST, ($method == "POST"));
+ if ($method == "POST") curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+ $response = curl_exec($curl);
+
+ if (curl_errno($curl) == 0){
+ $response;
+ }else{
+ $this->ErrorStore('OPENID_CURL', curl_error($curl));
+ }
+ return $response;
+ }
+
+ function HTML2OpenIDServer($content) {
+ $get = array();
+
+ // Get details of their OpenID server and (optional) delegate
+ preg_match_all('/<link[^>]*rel=[\'"](openid2.provider )?openid.server[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
+ preg_match_all('/<link[^>]*href=\'"([^\'"]+)[\'"][^>]*rel=[\'"](openid2.provider )?openid.server[\'"][^>]*\/?>/i', $content, $matches2);
+ $servers = array_merge($matches1[2], $matches2[1]);
+
+ preg_match_all('/<link[^>]*rel=[\'"]openid.delegate[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
+
+ preg_match_all('/<link[^>]*href=[\'"]([^\'"]+)[\'"][^>]*rel=[\'"]openid.delegate[\'"][^>]*\/?>/i', $content, $matches2);
+
+ $delegates = array_merge($matches1[1], $matches2[1]);
+
+ $ret = array($servers, $delegates);
+ return $ret;
+ }
+
+ function GetOpenIDServer(){
+ $response = $this->CURL_Request($this->openid_url_identity);
+ list($servers, $delegates) = $this->HTML2OpenIDServer($response);
+ if (count($servers) == 0){
+ $this->ErrorStore('OPENID_NOSERVERSFOUND');
+ return false;
+ }
+ if (isset($delegates[0])
+ && ($delegates[0] != "")){
+ $this->SetIdentity($delegates[0]);
+ }
+ $this->SetOpenIDServer($servers[0]);
+ return $servers[0];
+ }
+
+ function GetRedirectURL(){
+ $params = array();
+ $params['openid.return_to'] = urlencode($this->URLs['approved']);
+ $params['openid.mode'] = 'checkid_setup';
+ $params['openid.identity'] = urlencode($this->openid_url_identity);
+ $params['openid.trust_root'] = urlencode($this->URLs['trust_root']);
+
+ if (isset($this->fields['required'])
+ && (count($this->fields['required']) > 0)) {
+ $params['openid.sreg.required'] = implode(',',$this->fields['required']);
+ }
+ if (isset($this->fields['optional'])
+ && (count($this->fields['optional']) > 0)) {
+ $params['openid.sreg.optional'] = implode(',',$this->fields['optional']);
+ }
+ return $this->URLs['openid_server'] . "?". $this->array2url($params);
+ }
+
+ function Redirect(){
+ $redirect_to = $this->GetRedirectURL();
+ if (headers_sent()){ // Use JavaScript to redirect if content has been previously sent (not recommended, but safe)
+ echo '<script language="JavaScript" type="text/javascript">window.location=\'';
+ echo $redirect_to;
+ echo '\';</script>';
+ }else{ // Default Header Redirect
+ header('Location: ' . $redirect_to);
+ }
+ }
+
+ function ValidateWithServer(){
+ $params = array(
+ 'openid.assoc_handle' => urlencode($_GET['openid_assoc_handle']),
+ 'openid.signed' => urlencode($_GET['openid_signed']),
+ 'openid.sig' => urlencode($_GET['openid_sig'])
+ );
+ // Send only required parameters to confirm validity
+ $arr_signed = explode(",",str_replace('sreg.','sreg_',$_GET['openid_signed']));
+ for ($i=0; $i<count($arr_signed); $i++){
+ $s = str_replace('sreg_','sreg.', $arr_signed[$i]);
+ $c = $_GET['openid_' . $arr_signed[$i]];
+ // if ($c != ""){
+ $params['openid.' . $s] = urlencode($c);
+ // }
+ }
+ $params['openid.mode'] = "check_authentication";
+
+ $openid_server = $this->GetOpenIDServer();
+ if ($openid_server == false){
+ return false;
+ }
+ $response = $this->CURL_Request($openid_server,'POST',$params);
+ $data = $this->splitResponse($response);
+
+ if ($data['is_valid'] == "true") {
+ return true;
+ }else{
+ return false;
+ }
+ }
+}
diff --git a/3rdparty/openid/phpmyid.php b/3rdparty/openid/phpmyid.php
new file mode 100644
index 00000000000..13fd31c47ca
--- /dev/null
+++ b/3rdparty/openid/phpmyid.php
@@ -0,0 +1,1707 @@
+<?php
+// PLEASE DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING!
+
+/**
+ * phpMyID - A standalone, single user, OpenID Identity Provider
+ *
+ * @package phpMyID
+ * @author CJ Niemira <siege (at) siege (dot) org>
+ * @copyright 2006-2008
+ * @license http://www.gnu.org/licenses/gpl.html GNU Public License
+ * @url http://siege.org/projects/phpMyID
+ * @version 0.9
+ */
+
+/**
+ * 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',
+ '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_redirect($_SESSION['post_accept_url']);
+
+ // if they rejected it, return to the client
+ } elseif ($accepted === 'no') {
+ wrap_redirect($_SESSION['cancel_accept_url']);
+ }
+
+ // if neither, offer the trust request
+ $q = strpos($profile['req_url'], '?') ? '&' : '?';
+ $yes = $profile['req_url'] . $q . 'accepted=yes';
+ $no = $profile['req_url'] . $q . '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>');
+}
+
+/** * 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;
+ global $USERNAME;
+ global $IDENTITY;
+
+ // this is a 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.');
+
+ $profile['idp_url']=$IDENTITY;
+ if (isset($_SERVER['PHP_AUTH_USER']) && $profile['authorized'] === false && $_SERVER['PHP_AUTH_USER']==$USERNAME) {
+ if (OCP\User::checkPassword($USERNAME, $_SERVER['PHP_AUTH_PW'])) {// successful login!
+ // return to the refresh url if they get in
+ $_SESSION['openid_auth']=true;
+ $_SESSION['openid_user']=$USERNAME;
+ wrap_redirect($_SESSION['post_auth_url']);
+
+ // failed login
+ } else {
+ $_SESSION['failures']++;
+ debug('Login failed');
+ debug('Fail count: ' . $_SESSION['failures']);
+ }
+
+ }
+
+ // if we get this far the user is not authorized, so send the headers
+ $uid = uniqid(mt_rand(1,9));
+ $_SESSION['uniqid'] = $uid;
+
+// debug('Prompting user to log in. Stale? ' . $stale);
+ header('HTTP/1.0 401 Unauthorized');
+// header(sprintf('WWW-Authenticate: Digest qop="auth-int, auth", realm="%s", domain="%s", nonce="%s", opaque="%s", stale="%s", algorithm="MD5"', $profile['auth_realm'], $profile['auth_domain'], $uid, md5($profile['auth_realm']), $stale ? 'true' : 'false'));
+ header('WWW-Authenticate: Basic realm="ownCloud"');
+ $q = strpos($_SESSION['cancel_auth_url'], '?') ? '&' : '?';
+ wrap_refresh($_SESSION['cancel_auth_url'] . $q . 'openid.mode=cancel');
+// die('401 Unauthorized');
+}
+
+
+/**
+ * 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 ) {
+ global $known, $profile, $sreg;
+ global $USERNAME;
+
+ // This is a user session
+ user_session();
+
+ // Get the options, use defaults as necessary
+ $return_to = isset($_REQUEST['openid_return_to'])
+ ? $_REQUEST['openid_return_to']
+ : error_400('Missing return_to');
+
+ $identity = isset($_REQUEST['openid_identity'])
+ ? $_REQUEST['openid_identity']
+ : error_get($return_to, 'Missing identity');
+
+ $assoc_handle = isset($_REQUEST['openid_assoc_handle'])
+ ? $_REQUEST['openid_assoc_handle']
+ : null;
+
+ $trust_root = isset($_REQUEST['openid_trust_root'])
+ ? $_REQUEST['openid_trust_root']
+ : $return_to;
+
+ $sreg_required = isset($_REQUEST['openid_sreg_required'])
+ ? $_REQUEST['openid_sreg.required']
+ : '';
+
+ $sreg_optional = isset($_REQUEST['openid_sreg_optional'])
+ ? $_REQUEST['openid_sreg.optional']
+ : '';
+
+ // determine the cancel url
+ $q = strpos($return_to, '?') ? '&' : '?';
+ $cancel_url = $return_to . $q . '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']);
+
+ $q = strpos($profile['idp_url'], '?') ? '&' : '?';
+ wrap_redirect($profile['idp_url'] . $q . 'openid.mode=accept');
+ }
+
+ // make sure i am this identifier
+// if ($identity != $profile['idp_url']) {
+// debug("Invalid identity: $identity");
+// debug("IdP URL: " . $profile['idp_url']);
+// error_get($return_to, "Invalid identity: '$identity'");
+// }
+
+ // begin setting up return keys
+ $keys = array(
+ 'mode' => 'id_res'
+ );
+
+ // if the user is not logged in, transfer to the authorization mode
+ if ($USERNAME=='' || $_SESSION['openid_auth'] === false || $USERNAME != $_SESSION['openid_user']) {
+ // users can only be logged in to one url at a time
+ $_SESSION['openid_user'] = null;
+ $_SESSION['auth_url'] = null;
+
+ if ($wait) {
+ unset($_SESSION['uniqid']);
+
+ $_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']);
+
+ $q = strpos($profile['idp_url'], '?') ? '&' : '?';
+ wrap_redirect($profile['idp_url'] . $q . 'openid.mode=authorize');
+ } else {
+ $keys['user_setup_url'] = $profile['idp_url'];
+ }
+
+ // the user is logged in
+ } else {
+ // 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'] = $profile['idp_url'];
+ $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_keyed_redirect($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 ' . $_SESSION['auth_username']);
+
+ wrap_html('You are not logged in');
+}
+
+
+/**
+ * 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_keyed_redirect($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_redirect($profile['idp_url']);
+}
+
+
+/**
+ * The default information screen
+ * @global array $profile
+ */
+function no_mode () {
+ global $USERNAME, $profile;
+ $tmpl = new OCP\Template( 'user_openid', 'nomode', 'guest' );
+ if(substr($profile['req_url'],-1,1)!=='/'){//the identity should always end with a /
+ $profile['req_url'].='/';
+ }
+ $tmpl->addHeader('link',array('rel'=>'openid.server', 'href'=>$profile['req_url']));
+ $tmpl->addHeader('link',array('rel'=>'openid.delegate', 'href'=>$profile['idp_url']));
+ $tmpl->assign('user',$USERNAME);
+ $tmpl->printPage();
+}
+
+
+/**
+ * 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';
+ }
+
+ // 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
+ @session_unregister('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 debug log: ' . $profile['logfile']);
+
+ if (is_array($x)) {
+ ob_start();
+ print_r($x);
+ $x = $m . ($m != null ? "\n" : '') . ob_get_clean();
+
+ } else {
+ $x .= "\n";
+ }
+}
+
+
+/**
+ * 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);
+ if (OCP\Config::getSystemValue( "forcessl", false )) {
+ ini_set("session.cookie_secure", "on");
+ }
+ 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_keyed_redirect($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();
+ }
+
+ if (OCP\Config::getSystemValue( "forcessl", false )) {
+ ini_set("session.cookie_secure", "on");
+ }
+ 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);
+ if (OCP\Config::getSystemValue( "forcessl", false )) {
+ ini_set("session.cookie_secure", "on");
+ }
+ 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) &! $profile["allow_$x"])
+// error_500("phpMyID is not compatible with '$x'");
+// }
+//
+// $keys = array('auth_username', 'auth_password');
+// 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;
+}
+
+/**
+ * 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);
+ 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 () {
+ global $proto, $profile;
+
+ session_name('phpMyID_Server');
+ if (OCP\Config::getSystemValue( "forcessl", false )) {
+ ini_set("session.cookie_secure", "on");
+ }
+ @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;
+ header('Content-Type: text/html; charset=' . $charset);
+ $html= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<title>phpMyID</title>
+<link rel="openid.server" href="' . $profile['req_url'] . '" />
+<link rel="openid.delegate" href="' . $profile['idp_url'] . '" />
+' . implode("\n", $profile['opt_headers']) . '
+<meta name="charset" content="' . $charset . '" />
+<meta name="robots" content="noindex,nofollow" />
+</head>
+<body>
+<p>' . $message . '</p>
+</body>
+</html>
+';
+ echo $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);
+}
+
+
+/**
+ * Redirect, with OpenID keys
+ * @param string $url
+ * @param array @keys
+ */
+function wrap_keyed_redirect ($url, $keys) {
+ $keys = append_openid($keys);
+ debug($keys, 'Location keys');
+
+ $q = strpos($url, '?') ? '&' : '?';
+ wrap_redirect($url . $q . http_build_query($keys));
+}
+
+
+/**
+ * Redirect the browser
+ * @global string $charset
+ * @param string $url
+ */
+function wrap_redirect ($url) {
+ header('HTTP/1.1 302 Found');
+ header('Location: ' . $url);
+ debug('Location: ' . $url);
+ exit(0);
+}
+
+/**
+ * Return an HTML refresh
+ * @global string $charset
+ * @param string $url
+ */
+function wrap_refresh ($url) {
+ global $charset;
+
+ 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>phpMyID</title>
+<meta http-equiv="refresh" content="0;url=' . $url . '">
+</head>
+<body>
+<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;
+}
+
+
+
+/*
+ * 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'];
+
+
+/**
+ * Determine the HTTP request protocol
+ * @name $proto
+ * @global string $GLOBALS['proto']
+ */
+$GLOBALS['proto'] = (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == 'on') ? 'https' : 'http';
+
+// Set the authorization state - DO NOT OVERRIDE
+$profile['authorized'] = false;
+
+global $IDENTITY;
+global $USERNAME;
+
+// Set a default IDP URL
+if (! array_key_exists('idp_url', $profile))
+ $profile['idp_url'] = $IDENTITY;
+
+//Determine the requested URL - DO NOT OVERRIDE
+$profile['req_url'] = sprintf("%s://%s%s",
+ $proto,
+ OCP\Util::getServerHost(),
+// $port,//host already includes the path
+ $_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'] = 'ownCloud';
+
+// Determine the realm for digest 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;
+}
+
+// Set a default log file
+if (! array_key_exists('logfile', $profile))
+ $profile['logfile'] = get_temp_dir() . DIRECTORY_SEPARATOR . $profile['auth_realm'] . '.debug.log';
+
+
+/*
+ * 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');
+call_user_func($run_mode . '_mode');