CC-2166: Packaging Improvements. Moved the Zend app into airtime_mvc. It is now installed to /var/www/airtime. Storage is now set to /srv/airtime/stor. Utils are now installed to /usr/lib/airtime/utils/. Added install/airtime-dircheck.php as a simple test to see if everything is install/uninstalled correctly.

This commit is contained in:
Paul Baranowski 2011-04-14 18:55:04 -04:00
parent 514777e8d2
commit b11cbd8159
4546 changed files with 138 additions and 51 deletions

View file

@ -0,0 +1,958 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Consumer.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_OpenId
*/
require_once "Zend/OpenId.php";
/**
* @see Zend_OpenId_Extension
*/
require_once "Zend/OpenId/Extension.php";
/**
* @see Zend_OpenId_Consumer_Storage
*/
require_once "Zend/OpenId/Consumer/Storage.php";
/**
* @see Zend_Http_Client
*/
require_once 'Zend/Http/Client.php';
/**
* OpenID consumer implementation
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Consumer
{
/**
* Reference to an implementation of storage object
*
* @var Zend_OpenId_Consumer_Storage $_storage
*/
protected $_storage = null;
/**
* Enables or disables consumer to use association with server based on
* Diffie-Hellman key agreement
*
* @var Zend_OpenId_Consumer_Storage $_dumbMode
*/
protected $_dumbMode = false;
/**
* Internal cache to prevent unnecessary access to storage
*
* @var array $_cache
*/
protected $_cache = array();
/**
* HTTP client to make HTTP requests
*
* @var Zend_Http_Client $_httpClient
*/
private $_httpClient = null;
/**
* HTTP session to store climed_id between requests
*
* @var Zend_Session_Namespace $_session
*/
private $_session = null;
/**
* Last error message for logi, check or verify failure
*
* @var string $_error
*/
private $_error = '';
/**
* Constructs a Zend_OpenId_Consumer object with given $storage.
* Enables or disables future association with server based on
* Diffie-Hellman key agreement.
*
* @param Zend_OpenId_Consumer_Storage $storage implementation of custom
* storage object
* @param bool $dumbMode Enables or disables consumer to use association
* with server based on Diffie-Hellman key agreement
*/
public function __construct(Zend_OpenId_Consumer_Storage $storage = null,
$dumbMode = false)
{
if ($storage === null) {
require_once "Zend/OpenId/Consumer/Storage/File.php";
$this->_storage = new Zend_OpenId_Consumer_Storage_File();
} else {
$this->_storage = $storage;
}
$this->_dumbMode = $dumbMode;
}
/**
* Performs check (with possible user interaction) of OpenID identity.
*
* This is the first step of OpenID authentication process.
* On success the function does not return (it does HTTP redirection to
* server and exits). On failure it returns false.
*
* @param string $id OpenID identity
* @param string $returnTo URL to redirect response from server to
* @param string $root HTTP URL to identify consumer on server
* @param mixed $extensions extension object or array of extensions objects
* @param Zend_Controller_Response_Abstract $response an optional response
* object to perform HTTP or HTML form redirection
* @return bool
*/
public function login($id, $returnTo = null, $root = null, $extensions = null,
Zend_Controller_Response_Abstract $response = null)
{
return $this->_checkId(
false,
$id,
$returnTo,
$root,
$extensions,
$response);
}
/**
* Performs immediate check (without user interaction) of OpenID identity.
*
* This is the first step of OpenID authentication process.
* On success the function does not return (it does HTTP redirection to
* server and exits). On failure it returns false.
*
* @param string $id OpenID identity
* @param string $returnTo HTTP URL to redirect response from server to
* @param string $root HTTP URL to identify consumer on server
* @param mixed $extensions extension object or array of extensions objects
* @param Zend_Controller_Response_Abstract $response an optional response
* object to perform HTTP or HTML form redirection
* @return bool
*/
public function check($id, $returnTo=null, $root=null, $extensions = null,
Zend_Controller_Response_Abstract $response = null)
{
return $this->_checkId(
true,
$id,
$returnTo,
$root,
$extensions,
$response);
}
/**
* Verifies authentication response from OpenID server.
*
* This is the second step of OpenID authentication process.
* The function returns true on successful authentication and false on
* failure.
*
* @param array $params HTTP query data from OpenID server
* @param string &$identity this argument is set to end-user's claimed
* identifier or OpenID provider local identifier.
* @param mixed $extensions extension object or array of extensions objects
* @return bool
*/
public function verify($params, &$identity = "", $extensions = null)
{
$this->_setError('');
$version = 1.1;
if (isset($params['openid_ns']) &&
$params['openid_ns'] == Zend_OpenId::NS_2_0) {
$version = 2.0;
}
if (isset($params["openid_claimed_id"])) {
$identity = $params["openid_claimed_id"];
} else if (isset($params["openid_identity"])){
$identity = $params["openid_identity"];
} else {
$identity = "";
}
if ($version < 2.0 && !isset($params["openid_claimed_id"])) {
if ($this->_session !== null) {
if ($this->_session->identity === $identity) {
$identity = $this->_session->claimed_id;
}
} else if (defined('SID')) {
if (isset($_SESSION["zend_openid"]["identity"]) &&
isset($_SESSION["zend_openid"]["claimed_id"]) &&
$_SESSION["zend_openid"]["identity"] === $identity) {
$identity = $_SESSION["zend_openid"]["claimed_id"];
}
} else {
require_once "Zend/Session/Namespace.php";
$this->_session = new Zend_Session_Namespace("zend_openid");
if ($this->_session->identity === $identity) {
$identity = $this->_session->claimed_id;
}
}
}
if (empty($params['openid_mode'])) {
$this->_setError("Missing openid.mode");
return false;
}
if (empty($params['openid_return_to'])) {
$this->_setError("Missing openid.return_to");
return false;
}
if (empty($params['openid_signed'])) {
$this->_setError("Missing openid.signed");
return false;
}
if (empty($params['openid_sig'])) {
$this->_setError("Missing openid.sig");
return false;
}
if ($params['openid_mode'] != 'id_res') {
$this->_setError("Wrong openid.mode '".$params['openid_mode']."' != 'id_res'");
return false;
}
if (empty($params['openid_assoc_handle'])) {
$this->_setError("Missing openid.assoc_handle");
return false;
}
if ($params['openid_return_to'] != Zend_OpenId::selfUrl()) {
/* Ignore query part in openid.return_to */
$pos = strpos($params['openid_return_to'], '?');
if ($pos === false ||
SUBSTR($params['openid_return_to'], 0 , $pos) != Zend_OpenId::selfUrl()) {
$this->_setError("Wrong openid.return_to '".
$params['openid_return_to']."' != '" . Zend_OpenId::selfUrl() ."'");
return false;
}
}
if ($version >= 2.0) {
if (empty($params['openid_response_nonce'])) {
$this->_setError("Missing openid.response_nonce");
return false;
}
if (empty($params['openid_op_endpoint'])) {
$this->_setError("Missing openid.op_endpoint");
return false;
/* OpenID 2.0 (11.3) Checking the Nonce */
} else if (!$this->_storage->isUniqueNonce($params['openid_op_endpoint'], $params['openid_response_nonce'])) {
$this->_setError("Duplicate openid.response_nonce");
return false;
}
}
if (!empty($params['openid_invalidate_handle'])) {
if ($this->_storage->getAssociationByHandle(
$params['openid_invalidate_handle'],
$url,
$macFunc,
$secret,
$expires)) {
$this->_storage->delAssociation($url);
}
}
if ($this->_storage->getAssociationByHandle(
$params['openid_assoc_handle'],
$url,
$macFunc,
$secret,
$expires)) {
$signed = explode(',', $params['openid_signed']);
$data = '';
foreach ($signed as $key) {
$data .= $key . ':' . $params['openid_' . strtr($key,'.','_')] . "\n";
}
if (base64_decode($params['openid_sig']) ==
Zend_OpenId::hashHmac($macFunc, $data, $secret)) {
if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
$this->_setError("Extension::parseResponse failure");
return false;
}
/* OpenID 2.0 (11.2) Verifying Discovered Information */
if (isset($params['openid_claimed_id'])) {
$id = $params['openid_claimed_id'];
if (!Zend_OpenId::normalize($id)) {
$this->_setError("Normalization failed");
return false;
} else if (!$this->_discovery($id, $discovered_server, $discovered_version)) {
$this->_setError("Discovery failed: " . $this->getError());
return false;
} else if ((!empty($params['openid_identity']) &&
$params["openid_identity"] != $id) ||
(!empty($params['openid_op_endpoint']) &&
$params['openid_op_endpoint'] != $discovered_server) ||
$discovered_version != $version) {
$this->_setError("Discovery information verification failed");
return false;
}
}
return true;
}
$this->_storage->delAssociation($url);
$this->_setError("Signature check failed");
return false;
}
else
{
/* Use dumb mode */
if (isset($params['openid_claimed_id'])) {
$id = $params['openid_claimed_id'];
} else if (isset($params['openid_identity'])) {
$id = $params['openid_identity'];
} else {
$this->_setError("Missing openid.claimed_id and openid.identity");
return false;
}
if (!Zend_OpenId::normalize($id)) {
$this->_setError("Normalization failed");
return false;
} else if (!$this->_discovery($id, $server, $discovered_version)) {
$this->_setError("Discovery failed: " . $this->getError());
return false;
}
/* OpenID 2.0 (11.2) Verifying Discovered Information */
if ((isset($params['openid_identity']) &&
$params["openid_identity"] != $id) ||
(isset($params['openid_op_endpoint']) &&
$params['openid_op_endpoint'] != $server) ||
$discovered_version != $version) {
$this->_setError("Discovery information verification failed");
return false;
}
$params2 = array();
foreach ($params as $key => $val) {
if (strpos($key, 'openid_ns_') === 0) {
$key = 'openid.ns.' . substr($key, strlen('openid_ns_'));
} else if (strpos($key, 'openid_sreg_') === 0) {
$key = 'openid.sreg.' . substr($key, strlen('openid_sreg_'));
} else if (strpos($key, 'openid_') === 0) {
$key = 'openid.' . substr($key, strlen('openid_'));
}
$params2[$key] = $val;
}
$params2['openid.mode'] = 'check_authentication';
$ret = $this->_httpRequest($server, 'POST', $params2, $status);
if ($status != 200) {
$this->_setError("'Dumb' signature verification HTTP request failed");
return false;
}
$r = array();
if (is_string($ret)) {
foreach(explode("\n", $ret) as $line) {
$line = trim($line);
if (!empty($line)) {
$x = explode(':', $line, 2);
if (is_array($x) && count($x) == 2) {
list($key, $value) = $x;
$r[trim($key)] = trim($value);
}
}
}
}
$ret = $r;
if (!empty($ret['invalidate_handle'])) {
if ($this->_storage->getAssociationByHandle(
$ret['invalidate_handle'],
$url,
$macFunc,
$secret,
$expires)) {
$this->_storage->delAssociation($url);
}
}
if (isset($ret['is_valid']) && $ret['is_valid'] == 'true') {
if (!Zend_OpenId_Extension::forAll($extensions, 'parseResponse', $params)) {
$this->_setError("Extension::parseResponse failure");
return false;
}
return true;
}
$this->_setError("'Dumb' signature verification failed");
return false;
}
}
/**
* Store assiciation in internal chace and external storage
*
* @param string $url OpenID server url
* @param string $handle association handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param integer $expires expiration UNIX time
* @return void
*/
protected function _addAssociation($url, $handle, $macFunc, $secret, $expires)
{
$this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
return $this->_storage->addAssociation(
$url,
$handle,
$macFunc,
$secret,
$expires);
}
/**
* Retrive assiciation information for given $url from internal cahce or
* external storage
*
* @param string $url OpenID server url
* @param string &$handle association handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param integer &$expires expiration UNIX time
* @return void
*/
protected function _getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
{
if (isset($this->_cache[$url])) {
$handle = $this->_cache[$url][0];
$macFunc = $this->_cache[$url][1];
$secret = $this->_cache[$url][2];
$expires = $this->_cache[$url][3];
return true;
}
if ($this->_storage->getAssociation(
$url,
$handle,
$macFunc,
$secret,
$expires)) {
$this->_cache[$url] = array($handle, $macFunc, $secret, $expires);
return true;
}
return false;
}
/**
* Performs HTTP request to given $url using given HTTP $method.
* Send additinal query specified by variable/value array,
* On success returns HTTP response without headers, false on failure.
*
* @param string $url OpenID server url
* @param string $method HTTP request method 'GET' or 'POST'
* @param array $params additional qwery parameters to be passed with
* @param int &$staus HTTP status code
* request
* @return mixed
*/
protected function _httpRequest($url, $method = 'GET', array $params = array(), &$status = null)
{
$client = $this->_httpClient;
if ($client === null) {
$client = new Zend_Http_Client(
$url,
array(
'maxredirects' => 4,
'timeout' => 15,
'useragent' => 'Zend_OpenId'
)
);
} else {
$client->setUri($url);
}
$client->resetParameters();
if ($method == 'POST') {
$client->setMethod(Zend_Http_Client::POST);
$client->setParameterPost($params);
} else {
$client->setMethod(Zend_Http_Client::GET);
$client->setParameterGet($params);
}
try {
$response = $client->request();
} catch (Exception $e) {
$this->_setError('HTTP Request failed: ' . $e->getMessage());
return false;
}
$status = $response->getStatus();
$body = $response->getBody();
if ($status == 200 || ($status == 400 && !empty($body))) {
return $body;
}else{
$this->_setError('Bad HTTP response');
return false;
}
}
/**
* Create (or reuse existing) association between OpenID consumer and
* OpenID server based on Diffie-Hellman key agreement. Returns true
* on success and false on failure.
*
* @param string $url OpenID server url
* @param float $version OpenID protocol version
* @param string $priv_key for testing only
* @return bool
*/
protected function _associate($url, $version, $priv_key=null)
{
/* Check if we already have association in chace or storage */
if ($this->_getAssociation(
$url,
$handle,
$macFunc,
$secret,
$expires)) {
return true;
}
if ($this->_dumbMode) {
/* Use dumb mode */
return true;
}
$params = array();
if ($version >= 2.0) {
$params = array(
'openid.ns' => Zend_OpenId::NS_2_0,
'openid.mode' => 'associate',
'openid.assoc_type' => 'HMAC-SHA256',
'openid.session_type' => 'DH-SHA256',
);
} else {
$params = array(
'openid.mode' => 'associate',
'openid.assoc_type' => 'HMAC-SHA1',
'openid.session_type' => 'DH-SHA1',
);
}
$dh = Zend_OpenId::createDhKey(pack('H*', Zend_OpenId::DH_P),
pack('H*', Zend_OpenId::DH_G),
$priv_key);
$dh_details = Zend_OpenId::getDhKeyDetails($dh);
$params['openid.dh_modulus'] = base64_encode(
Zend_OpenId::btwoc($dh_details['p']));
$params['openid.dh_gen'] = base64_encode(
Zend_OpenId::btwoc($dh_details['g']));
$params['openid.dh_consumer_public'] = base64_encode(
Zend_OpenId::btwoc($dh_details['pub_key']));
while(1) {
$ret = $this->_httpRequest($url, 'POST', $params, $status);
if ($ret === false) {
$this->_setError("HTTP request failed");
return false;
}
$r = array();
$bad_response = false;
foreach(explode("\n", $ret) as $line) {
$line = trim($line);
if (!empty($line)) {
$x = explode(':', $line, 2);
if (is_array($x) && count($x) == 2) {
list($key, $value) = $x;
$r[trim($key)] = trim($value);
} else {
$bad_response = true;
}
}
}
if ($bad_response && strpos($ret, 'Unknown session type') !== false) {
$r['error_code'] = 'unsupported-type';
}
$ret = $r;
if (isset($ret['error_code']) &&
$ret['error_code'] == 'unsupported-type') {
if ($params['openid.session_type'] == 'DH-SHA256') {
$params['openid.session_type'] = 'DH-SHA1';
$params['openid.assoc_type'] = 'HMAC-SHA1';
} else if ($params['openid.session_type'] == 'DH-SHA1') {
$params['openid.session_type'] = 'no-encryption';
} else {
$this->_setError("The OpenID service responded with: " . $ret['error_code']);
return false;
}
} else {
break;
}
}
if ($status != 200) {
$this->_setError("The server responded with status code: " . $status);
return false;
}
if ($version >= 2.0 &&
isset($ret['ns']) &&
$ret['ns'] != Zend_OpenId::NS_2_0) {
$this->_setError("Wrong namespace definition in the server response");
return false;
}
if (!isset($ret['assoc_handle']) ||
!isset($ret['expires_in']) ||
!isset($ret['assoc_type']) ||
$params['openid.assoc_type'] != $ret['assoc_type']) {
if ($params['openid.assoc_type'] != $ret['assoc_type']) {
$this->_setError("The returned assoc_type differed from the supplied openid.assoc_type");
} else {
$this->_setError("Missing required data from provider (assoc_handle, expires_in, assoc_type are required)");
}
return false;
}
$handle = $ret['assoc_handle'];
$expiresIn = $ret['expires_in'];
if ($ret['assoc_type'] == 'HMAC-SHA1') {
$macFunc = 'sha1';
} else if ($ret['assoc_type'] == 'HMAC-SHA256' &&
$version >= 2.0) {
$macFunc = 'sha256';
} else {
$this->_setError("Unsupported assoc_type");
return false;
}
if ((empty($ret['session_type']) ||
($version >= 2.0 && $ret['session_type'] == 'no-encryption')) &&
isset($ret['mac_key'])) {
$secret = base64_decode($ret['mac_key']);
} else if (isset($ret['session_type']) &&
$ret['session_type'] == 'DH-SHA1' &&
!empty($ret['dh_server_public']) &&
!empty($ret['enc_mac_key'])) {
$dhFunc = 'sha1';
} else if (isset($ret['session_type']) &&
$ret['session_type'] == 'DH-SHA256' &&
$version >= 2.0 &&
!empty($ret['dh_server_public']) &&
!empty($ret['enc_mac_key'])) {
$dhFunc = 'sha256';
} else {
$this->_setError("Unsupported session_type");
return false;
}
if (isset($dhFunc)) {
$serverPub = base64_decode($ret['dh_server_public']);
$dhSec = Zend_OpenId::computeDhSecret($serverPub, $dh);
if ($dhSec === false) {
$this->_setError("DH secret comutation failed");
return false;
}
$sec = Zend_OpenId::digest($dhFunc, $dhSec);
if ($sec === false) {
$this->_setError("Could not create digest");
return false;
}
$secret = $sec ^ base64_decode($ret['enc_mac_key']);
}
if ($macFunc == 'sha1') {
if (Zend_OpenId::strlen($secret) != 20) {
$this->_setError("The length of the sha1 secret must be 20");
return false;
}
} else if ($macFunc == 'sha256') {
if (Zend_OpenId::strlen($secret) != 32) {
$this->_setError("The length of the sha256 secret must be 32");
return false;
}
}
$this->_addAssociation(
$url,
$handle,
$macFunc,
$secret,
time() + $expiresIn);
return true;
}
/**
* Performs discovery of identity and finds OpenID URL, OpenID server URL
* and OpenID protocol version. Returns true on succees and false on
* failure.
*
* @param string &$id OpenID identity URL
* @param string &$server OpenID server URL
* @param float &$version OpenID protocol version
* @return bool
* @todo OpenID 2.0 (7.3) XRI and Yadis discovery
*/
protected function _discovery(&$id, &$server, &$version)
{
$realId = $id;
if ($this->_storage->getDiscoveryInfo(
$id,
$realId,
$server,
$version,
$expire)) {
$id = $realId;
return true;
}
/* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
/* HTML-based discovery */
$response = $this->_httpRequest($id, 'GET', array(), $status);
if ($status != 200 || !is_string($response)) {
return false;
}
if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$response,
$r)) {
$version = 2.0;
$server = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.provider[ \t]*[^"\']*\\3[^>]*\/?>/i',
$response,
$r)) {
$version = 2.0;
$server = $r[2];
} else if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$response,
$r)) {
$version = 1.1;
$server = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.server[ \t]*[^"\']*\\3[^>]*\/?>/i',
$response,
$r)) {
$version = 1.1;
$server = $r[2];
} else {
return false;
}
if ($version >= 2.0) {
if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$response,
$r)) {
$realId = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid2.local_id[ \t]*[^"\']*\\3[^>]*\/?>/i',
$response,
$r)) {
$realId = $r[2];
}
} else {
if (preg_match(
'/<link[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\1[^>]*href=(["\'])([^"\']+)\\2[^>]*\/?>/i',
$response,
$r)) {
$realId = $r[3];
} else if (preg_match(
'/<link[^>]*href=(["\'])([^"\']+)\\1[^>]*rel=(["\'])[ \t]*(?:[^ \t"\']+[ \t]+)*?openid.delegate[ \t]*[^"\']*\\3[^>]*\/?>/i',
$response,
$r)) {
$realId = $r[2];
}
}
$expire = time() + 60 * 60;
$this->_storage->addDiscoveryInfo($id, $realId, $server, $version, $expire);
$id = $realId;
return true;
}
/**
* Performs check of OpenID identity.
*
* This is the first step of OpenID authentication process.
* On success the function does not return (it does HTTP redirection to
* server and exits). On failure it returns false.
*
* @param bool $immediate enables or disables interaction with user
* @param string $id OpenID identity
* @param string $returnTo HTTP URL to redirect response from server to
* @param string $root HTTP URL to identify consumer on server
* @param mixed $extensions extension object or array of extensions objects
* @param Zend_Controller_Response_Abstract $response an optional response
* object to perform HTTP or HTML form redirection
* @return bool
*/
protected function _checkId($immediate, $id, $returnTo=null, $root=null,
$extensions=null, Zend_Controller_Response_Abstract $response = null)
{
$this->_setError('');
if (!Zend_OpenId::normalize($id)) {
$this->_setError("Normalisation failed");
return false;
}
$claimedId = $id;
if (!$this->_discovery($id, $server, $version)) {
$this->_setError("Discovery failed: " . $this->getError());
return false;
}
if (!$this->_associate($server, $version)) {
$this->_setError("Association failed: " . $this->getError());
return false;
}
if (!$this->_getAssociation(
$server,
$handle,
$macFunc,
$secret,
$expires)) {
/* Use dumb mode */
unset($handle);
unset($macFunc);
unset($secret);
unset($expires);
}
$params = array();
if ($version >= 2.0) {
$params['openid.ns'] = Zend_OpenId::NS_2_0;
}
$params['openid.mode'] = $immediate ?
'checkid_immediate' : 'checkid_setup';
$params['openid.identity'] = $id;
$params['openid.claimed_id'] = $claimedId;
if ($version <= 2.0) {
if ($this->_session !== null) {
$this->_session->identity = $id;
$this->_session->claimed_id = $claimedId;
} else if (defined('SID')) {
$_SESSION["zend_openid"] = array(
"identity" => $id,
"claimed_id" => $claimedId);
} else {
require_once "Zend/Session/Namespace.php";
$this->_session = new Zend_Session_Namespace("zend_openid");
$this->_session->identity = $id;
$this->_session->claimed_id = $claimedId;
}
}
if (isset($handle)) {
$params['openid.assoc_handle'] = $handle;
}
$params['openid.return_to'] = Zend_OpenId::absoluteUrl($returnTo);
if (empty($root)) {
$root = Zend_OpenId::selfUrl();
if ($root[strlen($root)-1] != '/') {
$root = dirname($root);
}
}
if ($version >= 2.0) {
$params['openid.realm'] = $root;
} else {
$params['openid.trust_root'] = $root;
}
if (!Zend_OpenId_Extension::forAll($extensions, 'prepareRequest', $params)) {
$this->_setError("Extension::prepareRequest failure");
return false;
}
Zend_OpenId::redirect($server, $params, $response);
return true;
}
/**
* Sets HTTP client object to make HTTP requests
*
* @param Zend_Http_Client $client HTTP client object to be used
*/
public function setHttpClient($client) {
$this->_httpClient = $client;
}
/**
* Returns HTTP client object that will be used to make HTTP requests
*
* @return Zend_Http_Client
*/
public function getHttpClient() {
return $this->_httpClient;
}
/**
* Sets session object to store climed_id
*
* @param Zend_Session_Namespace $session HTTP client object to be used
*/
public function setSession(Zend_Session_Namespace $session) {
$this->_session = $session;
}
/**
* Returns session object that is used to store climed_id
*
* @return Zend_Session_Namespace
*/
public function getSession() {
return $this->_session;
}
/**
* Saves error message
*
* @param string $message error message
*/
protected function _setError($message)
{
$this->_error = $message;
}
/**
* Returns error message that explains failure of login, check or verify
*
* @return string
*/
public function getError()
{
return $this->_error;
}
}

View file

@ -0,0 +1,132 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Storage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* Abstract class to implement external storage for OpenID consumer
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_OpenId_Consumer_Storage
{
/**
* Stores information about association identified by $url/$handle
*
* @param string $url OpenID server URL
* @param string $handle assiciation handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param long $expires expiration UNIX time
* @return void
*/
abstract public function addAssociation($url, $handle, $macFunc, $secret, $expires);
/**
* Gets information about association identified by $url
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $url OpenID server URL
* @param string &$handle assiciation handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
abstract public function getAssociation($url, &$handle, &$macFunc, &$secret, &$expires);
/**
* Gets information about association identified by $handle
* Returns true if given association found and not expired and false
* othverwise
*
* @param string $handle assiciation handle
* @param string &$url OpenID server URL
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
abstract public function getAssociationByHandle($handle, &$url, &$macFunc, &$secret, &$expires);
/**
* Deletes association identified by $url
*
* @param string $url OpenID server URL
* @return void
*/
abstract public function delAssociation($url);
/**
* Stores information discovered from identity $id
*
* @param string $id identity
* @param string $realId discovered real identity URL
* @param string $server discovered OpenID server URL
* @param float $version discovered OpenID protocol version
* @param long $expires expiration UNIX time
* @return void
*/
abstract public function addDiscoveryInfo($id, $realId, $server, $version, $expires);
/**
* Gets information discovered from identity $id
* Returns true if such information exists and false otherwise
*
* @param string $id identity
* @param string &$realId discovered real identity URL
* @param string &$server discovered OpenID server URL
* @param float &$version discovered OpenID protocol version
* @param long &$expires expiration UNIX time
* @return bool
*/
abstract public function getDiscoveryInfo($id, &$realId, &$server, &$version, &$expires);
/**
* Removes cached information discovered from identity $id
*
* @param string $id identity
* @return bool
*/
abstract public function delDiscoveryInfo($id);
/**
* The function checks the uniqueness of openid.response_nonce
*
* @param string $provider openid.openid_op_endpoint field from authentication response
* @param string $nonce openid.response_nonce field from authentication response
* @return bool
*/
abstract public function isUniqueNonce($provider, $nonce);
/**
* Removes data from the uniqueness database that is older then given date
*
* @param string $date Date of expired data
*/
abstract public function purgeNonces($date=null);
}

View file

@ -0,0 +1,507 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_OpenId_Consumer_Storage
*/
require_once "Zend/OpenId/Consumer/Storage.php";
/**
* External storage implemmentation using serialized files
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Consumer
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Consumer_Storage_File extends Zend_OpenId_Consumer_Storage
{
/**
* Directory name to store data files in
*
* @var string $_dir
*/
private $_dir;
/**
* Constructs storage object and creates storage directory
*
* @param string $dir directory name to store data files in
* @throws Zend_OpenId_Exception
*/
public function __construct($dir = null)
{
if ($dir === null) {
$tmp = getenv('TMP');
if (empty($tmp)) {
$tmp = getenv('TEMP');
if (empty($tmp)) {
$tmp = "/tmp";
}
}
$user = get_current_user();
if (is_string($user) && !empty($user)) {
$tmp .= '/' . $user;
}
$dir = $tmp . '/openid/consumer';
}
$this->_dir = $dir;
if (!is_dir($this->_dir)) {
if (!@mkdir($this->_dir, 0700, 1)) {
/**
* @see Zend_OpenId_Exception
*/
require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot access storage directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
}
if (($f = fopen($this->_dir.'/assoc.lock', 'w+')) === null) {
/**
* @see Zend_OpenId_Exception
*/
require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
fclose($f);
if (($f = fopen($this->_dir.'/discovery.lock', 'w+')) === null) {
/**
* @see Zend_OpenId_Exception
*/
require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
fclose($f);
if (($f = fopen($this->_dir.'/nonce.lock', 'w+')) === null) {
/**
* @see Zend_OpenId_Exception
*/
require_once 'Zend/OpenId/Exception.php';
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
fclose($f);
}
/**
* Stores information about association identified by $url/$handle
*
* @param string $url OpenID server URL
* @param string $handle assiciation handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param long $expires expiration UNIX time
* @return bool
*/
public function addAssociation($url, $handle, $macFunc, $secret, $expires)
{
$name1 = $this->_dir . '/assoc_url_' . md5($url);
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name1, 'w+');
if ($f === false) {
fclose($lock);
return false;
}
$data = serialize(array($url, $handle, $macFunc, $secret, $expires));
fwrite($f, $data);
if (function_exists('symlink')) {
@unlink($name2);
if (symlink($name1, $name2)) {
fclose($f);
fclose($lock);
return true;
}
}
$f2 = @fopen($name2, 'w+');
if ($f2) {
fwrite($f2, $data);
fclose($f2);
@unlink($name1);
$ret = true;
} else {
$ret = false;
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Gets information about association identified by $url
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $url OpenID server URL
* @param string &$handle assiciation handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
public function getAssociation($url, &$handle, &$macFunc, &$secret, &$expires)
{
$name1 = $this->_dir . '/assoc_url_' . md5($url);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name1, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data);
if ($url === $storedUrl && $expires > time()) {
$ret = true;
} else {
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
fclose($f);
@unlink($name2);
@unlink($name1);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Gets information about association identified by $handle
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $handle assiciation handle
* @param string &$url OpenID server URL
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param long &$expires expiration UNIX time
* @return bool
*/
public function getAssociationByHandle($handle, &$url, &$macFunc, &$secret, &$expires)
{
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name2, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($url, $storedHandle, $macFunc, $secret, $expires) = unserialize($data);
if ($handle === $storedHandle && $expires > time()) {
$ret = true;
} else {
fclose($f);
@unlink($name2);
$name1 = $this->_dir . '/assoc_url_' . md5($url);
@unlink($name1);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Deletes association identified by $url
*
* @param string $url OpenID server URL
* @return bool
*/
public function delAssociation($url)
{
$name1 = $this->_dir . '/assoc_url_' . md5($url);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name1, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedUrl, $handle, $macFunc, $secret, $expires) = unserialize($data);
if ($url === $storedUrl) {
$name2 = $this->_dir . '/assoc_handle_' . md5($handle);
fclose($f);
@unlink($name2);
@unlink($name1);
fclose($lock);
return true;
}
}
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Stores information discovered from identity $id
*
* @param string $id identity
* @param string $realId discovered real identity URL
* @param string $server discovered OpenID server URL
* @param float $version discovered OpenID protocol version
* @param long $expires expiration UNIX time
* @return bool
*/
public function addDiscoveryInfo($id, $realId, $server, $version, $expires)
{
$name = $this->_dir . '/discovery_' . md5($id);
$lock = @fopen($this->_dir . '/discovery.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'w+');
if ($f === false) {
fclose($lock);
return false;
}
$data = serialize(array($id, $realId, $server, $version, $expires));
fwrite($f, $data);
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Gets information discovered from identity $id
* Returns true if such information exists and false otherwise
*
* @param string $id identity
* @param string &$realId discovered real identity URL
* @param string &$server discovered OpenID server URL
* @param float &$version discovered OpenID protocol version
* @param long &$expires expiration UNIX time
* @return bool
*/
public function getDiscoveryInfo($id, &$realId, &$server, &$version, &$expires)
{
$name = $this->_dir . '/discovery_' . md5($id);
$lock = @fopen($this->_dir . '/discovery.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedId, $realId, $server, $version, $expires) = unserialize($data);
if ($id === $storedId && $expires > time()) {
$ret = true;
} else {
fclose($f);
@unlink($name);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Removes cached information discovered from identity $id
*
* @param string $id identity
* @return bool
*/
public function delDiscoveryInfo($id)
{
$name = $this->_dir . '/discovery_' . md5($id);
$lock = @fopen($this->_dir . '/discovery.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
@unlink($name);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* The function checks the uniqueness of openid.response_nonce
*
* @param string $provider openid.openid_op_endpoint field from authentication response
* @param string $nonce openid.response_nonce field from authentication response
* @return bool
*/
public function isUniqueNonce($provider, $nonce)
{
$name = $this->_dir . '/nonce_' . md5($provider.';'.$nonce);
$lock = @fopen($this->_dir . '/nonce.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'x');
if ($f === false) {
fclose($lock);
return false;
}
fwrite($f, $provider.';'.$nonce);
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Removes data from the uniqueness database that is older then given date
*
* @param mixed $date date of expired data
*/
public function purgeNonces($date=null)
{
$lock = @fopen($this->_dir . '/nonce.lock', 'w+');
if ($lock !== false) {
flock($lock, LOCK_EX);
}
try {
if (!is_int($date) && !is_string($date)) {
foreach (glob($this->_dir . '/nonce_*') as $name) {
@unlink($name);
}
} else {
if (is_string($date)) {
$time = time($date);
} else {
$time = $date;
}
foreach (glob($this->_dir . '/nonce_*') as $name) {
if (filemtime($name) < $time) {
@unlink($name);
}
}
}
if ($lock !== false) {
fclose($lock);
}
} catch (Exception $e) {
if ($lock !== false) {
fclose($lock);
}
throw $e;
}
}
}

View file

@ -0,0 +1,58 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Exception.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_Exception
*/
require_once "Zend/Exception.php";
/**
* Exception class for Zend_OpenId
*
* @category Zend
* @package Zend_OpenId
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Exception extends Zend_Exception
{
/**
* The specified digest algotithm is not supported by this PHP installation
*/
const UNSUPPORTED_DIGEST = 1;
/**
* The long math arithmetick is not supported by this PHP installation
*/
const UNSUPPORTED_LONG_MATH = 2;
/**
* Internal long math arithmetic error
*/
const ERROR_LONG_MATH = 3;
/**
* Iternal storage error
*/
const ERROR_STORAGE = 4;
}

View file

@ -0,0 +1,137 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Extension.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* Abstract extension class for Zend_OpenId
*
* @category Zend
* @package Zend_OpenId
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_OpenId_Extension
{
/**
* Calls given function with given argument for all extensions
*
* @param mixed $extensions list of extensions or one extension
* @param string $func function to be called
* @param mixed &$params argument to pass to given funcion
* @return bool
*/
static public function forAll($extensions, $func, &$params)
{
if ($extensions !== null) {
if (is_array($extensions)) {
foreach ($extensions as $ext) {
if ($ext instanceof Zend_OpenId_Extension) {
if (!$ext->$func($params)) {
return false;
}
} else {
return false;
}
}
} else if (!is_object($extensions) ||
!($extensions instanceof Zend_OpenId_Extension) ||
!$extensions->$func($params)) {
return false;
}
}
return true;
}
/**
* Method to add additional data to OpenId 'checkid_immediate' or
* 'checkid_setup' request. This method addes nothing but inherited class
* may add additional data into request.
*
* @param array &$params request's var/val pairs
* @return bool
*/
public function prepareRequest(&$params)
{
return true;
}
/**
* Method to parse OpenId 'checkid_immediate' or 'checkid_setup' request
* and initialize object with passed data. This method parses nothing but
* inherited class may override this method to do somthing.
*
* @param array $params request's var/val pairs
* @return bool
*/
public function parseRequest($params)
{
return true;
}
/**
* Method to add additional data to OpenId 'id_res' response. This method
* addes nothing but inherited class may add additional data into response.
*
* @param array &$params response's var/val pairs
* @return bool
*/
public function prepareResponse(&$params)
{
return true;
}
/**
* Method to parse OpenId 'id_res' response and initialize object with
* passed data. This method parses nothing but inherited class may override
* this method to do somthing.
*
* @param array $params response's var/val pairs
* @return bool
*/
public function parseResponse($params)
{
return true;
}
/**
* Method to prepare data to store it in trusted servers database.
*
* @param array &$data data to be stored in tusted servers database
* @return bool
*/
public function getTrustData(&$data)
{
return true;
}
/**
* Method to check if data from trusted servers database is enough to
* sutisfy request.
*
* @param array $data data from tusted servers database
* @return bool
*/
public function checkTrustData($data)
{
return true;
}
}

View file

@ -0,0 +1,300 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Sreg.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_OpenId_Extension
*/
require_once "Zend/OpenId/Extension.php";
/**
* 'Simple Refistration Extension' for Zend_OpenId
*
* @category Zend
* @package Zend_OpenId
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Extension_Sreg extends Zend_OpenId_Extension
{
/**
* SREG 1.1 namespace. All OpenID SREG 1.1 messages MUST contain variable
* openid.ns.sreg with its value.
*/
const NAMESPACE_1_1 = "http://openid.net/extensions/sreg/1.1";
private $_props;
private $_policy_url;
private $_version;
/**
* Creates SREG extension object
*
* @param array $props associative array of SREG variables
* @param string $policy_url SREG policy URL
* @param float $version SREG version
* @return array
*/
public function __construct(array $props=null, $policy_url=null, $version=1.0)
{
$this->_props = $props;
$this->_policy_url = $policy_url;
$this->_version = $version;
}
/**
* Returns associative array of SREG variables
*
* @return array
*/
public function getProperties() {
if (is_array($this->_props)) {
return $this->_props;
} else {
return array();
}
}
/**
* Returns SREG policy URL
*
* @return string
*/
public function getPolicyUrl() {
return $this->_policy_url;
}
/**
* Returns SREG protocol version
*
* @return float
*/
public function getVersion() {
return $this->_version;
}
/**
* Returns array of allowed SREG variable names.
*
* @return array
*/
public static function getSregProperties()
{
return array(
"nickname",
"email",
"fullname",
"dob",
"gender",
"postcode",
"country",
"language",
"timezone"
);
}
/**
* Adds additional SREG data to OpenId 'checkid_immediate' or
* 'checkid_setup' request.
*
* @param array &$params request's var/val pairs
* @return bool
*/
public function prepareRequest(&$params)
{
if (is_array($this->_props) && count($this->_props) > 0) {
foreach ($this->_props as $prop => $req) {
if ($req) {
if (isset($required)) {
$required .= ','.$prop;
} else {
$required = $prop;
}
} else {
if (isset($optional)) {
$optional .= ','.$prop;
} else {
$optional = $prop;
}
}
}
if ($this->_version >= 1.1) {
$params['openid.ns.sreg'] = Zend_OpenId_Extension_Sreg::NAMESPACE_1_1;
}
if (!empty($required)) {
$params['openid.sreg.required'] = $required;
}
if (!empty($optional)) {
$params['openid.sreg.optional'] = $optional;
}
if (!empty($this->_policy_url)) {
$params['openid.sreg.policy_url'] = $this->_policy_url;
}
}
return true;
}
/**
* Parses OpenId 'checkid_immediate' or 'checkid_setup' request,
* extracts SREG variables and sets ovject properties to corresponding
* values.
*
* @param array $params request's var/val pairs
* @return bool
*/
public function parseRequest($params)
{
if (isset($params['openid_ns_sreg']) &&
$params['openid_ns_sreg'] === Zend_OpenId_Extension_Sreg::NAMESPACE_1_1) {
$this->_version= 1.1;
} else {
$this->_version= 1.0;
}
if (!empty($params['openid_sreg_policy_url'])) {
$this->_policy_url = $params['openid_sreg_policy_url'];
} else {
$this->_policy_url = null;
}
$props = array();
if (!empty($params['openid_sreg_optional'])) {
foreach (explode(',', $params['openid_sreg_optional']) as $prop) {
$prop = trim($prop);
$props[$prop] = false;
}
}
if (!empty($params['openid_sreg_required'])) {
foreach (explode(',', $params['openid_sreg_required']) as $prop) {
$prop = trim($prop);
$props[$prop] = true;
}
}
$props2 = array();
foreach (self::getSregProperties() as $prop) {
if (isset($props[$prop])) {
$props2[$prop] = $props[$prop];
}
}
$this->_props = (count($props2) > 0) ? $props2 : null;
return true;
}
/**
* Adds additional SREG data to OpenId 'id_res' response.
*
* @param array &$params response's var/val pairs
* @return bool
*/
public function prepareResponse(&$params)
{
if (is_array($this->_props) && count($this->_props) > 0) {
if ($this->_version >= 1.1) {
$params['openid.ns.sreg'] = Zend_OpenId_Extension_Sreg::NAMESPACE_1_1;
}
foreach (self::getSregProperties() as $prop) {
if (!empty($this->_props[$prop])) {
$params['openid.sreg.' . $prop] = $this->_props[$prop];
}
}
}
return true;
}
/**
* Parses OpenId 'id_res' response and sets object's properties according
* to 'openid.sreg.*' variables in response
*
* @param array $params response's var/val pairs
* @return bool
*/
public function parseResponse($params)
{
if (isset($params['openid_ns_sreg']) &&
$params['openid_ns_sreg'] === Zend_OpenId_Extension_Sreg::NAMESPACE_1_1) {
$this->_version= 1.1;
} else {
$this->_version= 1.0;
}
$props = array();
foreach (self::getSregProperties() as $prop) {
if (!empty($params['openid_sreg_' . $prop])) {
$props[$prop] = $params['openid_sreg_' . $prop];
}
}
if (isset($this->_props) && is_array($this->_props)) {
foreach (self::getSregProperties() as $prop) {
if (isset($this->_props[$prop]) &&
$this->_props[$prop] &&
!isset($props[$prop])) {
return false;
}
}
}
$this->_props = (count($props) > 0) ? $props : null;
return true;
}
/**
* Addes SREG properties that are allowed to be send to consumer to
* the given $data argument.
*
* @param array &$data data to be stored in tusted servers database
* @return bool
*/
public function getTrustData(&$data)
{
$data[get_class()] = $this->getProperties();
return true;
}
/**
* Check if given $data contains necessury SREG properties to sutisfy
* OpenId request. On success sets SREG response properties from given
* $data and returns true, on failure returns false.
*
* @param array $data data from tusted servers database
* @return bool
*/
public function checkTrustData($data)
{
if (is_array($this->_props) && count($this->_props) > 0) {
$props = array();
$name = get_class();
if (isset($data[$name])) {
$props = $data[$name];
} else {
$props = array();
}
$props2 = array();
foreach ($this->_props as $prop => $req) {
if (empty($props[$prop])) {
if ($req) {
return false;
}
} else {
$props2[$prop] = $props[$prop];
}
}
$this->_props = (count($props2) > 0) ? $props2 : null;
}
return true;
}
}

View file

@ -0,0 +1,781 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Provider.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_OpenId
*/
require_once "Zend/OpenId.php";
/**
* @see Zend_OpenId_Extension
*/
require_once "Zend/OpenId/Extension.php";
/**
* OpenID provider (server) implementation
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Provider
{
/**
* Reference to an implementation of storage object
*
* @var Zend_OpenId_Provider_Storage $_storage
*/
private $_storage;
/**
* Reference to an implementation of user object
*
* @var Zend_OpenId_Provider_User $_user
*/
private $_user;
/**
* Time to live of association session in secconds
*
* @var integer $_sessionTtl
*/
private $_sessionTtl;
/**
* URL to peform interactive user login
*
* @var string $_loginUrl
*/
private $_loginUrl;
/**
* URL to peform interactive validation of consumer by user
*
* @var string $_trustUrl
*/
private $_trustUrl;
/**
* The OP Endpoint URL
*
* @var string $_opEndpoint
*/
private $_opEndpoint;
/**
* Constructs a Zend_OpenId_Provider object with given parameters.
*
* @param string $loginUrl is an URL that provides login screen for
* end-user (by default it is the same URL with additional GET variable
* openid.action=login)
* @param string $trustUrl is an URL that shows a question if end-user
* trust to given consumer (by default it is the same URL with additional
* GET variable openid.action=trust)
* @param Zend_OpenId_Provider_User $user is an object for communication
* with User-Agent and store information about logged-in user (it is a
* Zend_OpenId_Provider_User_Session object by default)
* @param Zend_OpenId_Provider_Storage $storage is an object for keeping
* persistent database (it is a Zend_OpenId_Provider_Storage_File object
* by default)
* @param integer $sessionTtl is a default time to live for association
* session in seconds (1 hour by default). Consumer must reestablish
* association after that time.
*/
public function __construct($loginUrl = null,
$trustUrl = null,
Zend_OpenId_Provider_User $user = null,
Zend_OpenId_Provider_Storage $storage = null,
$sessionTtl = 3600)
{
if ($loginUrl === null) {
$loginUrl = Zend_OpenId::selfUrl() . '?openid.action=login';
} else {
$loginUrl = Zend_OpenId::absoluteUrl($loginUrl);
}
$this->_loginUrl = $loginUrl;
if ($trustUrl === null) {
$trustUrl = Zend_OpenId::selfUrl() . '?openid.action=trust';
} else {
$trustUrl = Zend_OpenId::absoluteUrl($trustUrl);
}
$this->_trustUrl = $trustUrl;
if ($user === null) {
require_once "Zend/OpenId/Provider/User/Session.php";
$this->_user = new Zend_OpenId_Provider_User_Session();
} else {
$this->_user = $user;
}
if ($storage === null) {
require_once "Zend/OpenId/Provider/Storage/File.php";
$this->_storage = new Zend_OpenId_Provider_Storage_File();
} else {
$this->_storage = $storage;
}
$this->_sessionTtl = $sessionTtl;
}
/**
* Sets the OP Endpoint URL
*
* @param string $url the OP Endpoint URL
* @return null
*/
public function setOpEndpoint($url)
{
$this->_opEndpoint = $url;
}
/**
* Registers a new user with given $id and $password
* Returns true in case of success and false if user with given $id already
* exists
*
* @param string $id user identity URL
* @param string $password encoded user password
* @return bool
*/
public function register($id, $password)
{
if (!Zend_OpenId::normalize($id) || empty($id)) {
return false;
}
return $this->_storage->addUser($id, md5($id.$password));
}
/**
* Returns true if user with given $id exists and false otherwise
*
* @param string $id user identity URL
* @return bool
*/
public function hasUser($id) {
if (!Zend_OpenId::normalize($id)) {
return false;
}
return $this->_storage->hasUser($id);
}
/**
* Performs login of user with given $id and $password
* Returns true in case of success and false otherwise
*
* @param string $id user identity URL
* @param string $password user password
* @return bool
*/
public function login($id, $password)
{
if (!Zend_OpenId::normalize($id)) {
return false;
}
if (!$this->_storage->checkUser($id, md5($id.$password))) {
return false;
}
$this->_user->setLoggedInUser($id);
return true;
}
/**
* Performs logout. Clears information about logged in user.
*
* @return void
*/
public function logout()
{
$this->_user->delLoggedInUser();
return true;
}
/**
* Returns identity URL of current logged in user or false
*
* @return mixed
*/
public function getLoggedInUser() {
return $this->_user->getLoggedInUser();
}
/**
* Retrieve consumer's root URL from request query.
* Returns URL or false in case of failure
*
* @param array $params query arguments
* @return mixed
*/
public function getSiteRoot($params)
{
$version = 1.1;
if (isset($params['openid_ns']) &&
$params['openid_ns'] == Zend_OpenId::NS_2_0) {
$version = 2.0;
}
if ($version >= 2.0 && isset($params['openid_realm'])) {
$root = $params['openid_realm'];
} else if ($version < 2.0 && isset($params['openid_trust_root'])) {
$root = $params['openid_trust_root'];
} else if (isset($params['openid_return_to'])) {
$root = $params['openid_return_to'];
} else {
return false;
}
if (Zend_OpenId::normalizeUrl($root) && !empty($root)) {
return $root;
}
return false;
}
/**
* Allows consumer with given root URL to authenticate current logged
* in user. Returns true on success and false on error.
*
* @param string $root root URL
* @param mixed $extensions extension object or array of extensions objects
* @return bool
*/
public function allowSite($root, $extensions=null)
{
$id = $this->getLoggedInUser();
if ($id === false) {
return false;
}
if ($extensions !== null) {
$data = array();
Zend_OpenId_Extension::forAll($extensions, 'getTrustData', $data);
} else {
$data = true;
}
$this->_storage->addSite($id, $root, $data);
return true;
}
/**
* Prohibit consumer with given root URL to authenticate current logged
* in user. Returns true on success and false on error.
*
* @param string $root root URL
* @return bool
*/
public function denySite($root)
{
$id = $this->getLoggedInUser();
if ($id === false) {
return false;
}
$this->_storage->addSite($id, $root, false);
return true;
}
/**
* Delete consumer with given root URL from known sites of current logged
* in user. Next time this consumer will try to authenticate the user,
* Provider will ask user's confirmation.
* Returns true on success and false on error.
*
* @param string $root root URL
* @return bool
*/
public function delSite($root)
{
$id = $this->getLoggedInUser();
if ($id === false) {
return false;
}
$this->_storage->addSite($id, $root, null);
return true;
}
/**
* Returns list of known consumers for current logged in user or false
* if he is not logged in.
*
* @return mixed
*/
public function getTrustedSites()
{
$id = $this->getLoggedInUser();
if ($id === false) {
return false;
}
return $this->_storage->getTrustedSites($id);
}
/**
* Handles HTTP request from consumer
*
* @param array $params GET or POST variables. If this parameter is omited
* or set to null, then $_GET or $_POST superglobal variable is used
* according to REQUEST_METHOD.
* @param mixed $extensions extension object or array of extensions objects
* @param Zend_Controller_Response_Abstract $response an optional response
* object to perform HTTP or HTML form redirection
* @return mixed
*/
public function handle($params=null, $extensions=null,
Zend_Controller_Response_Abstract $response = null)
{
if ($params === null) {
if ($_SERVER["REQUEST_METHOD"] == "GET") {
$params = $_GET;
} else if ($_SERVER["REQUEST_METHOD"] == "POST") {
$params = $_POST;
} else {
return false;
}
}
$version = 1.1;
if (isset($params['openid_ns']) &&
$params['openid_ns'] == Zend_OpenId::NS_2_0) {
$version = 2.0;
}
if (isset($params['openid_mode'])) {
if ($params['openid_mode'] == 'associate') {
$response = $this->_associate($version, $params);
$ret = '';
foreach ($response as $key => $val) {
$ret .= $key . ':' . $val . "\n";
}
return $ret;
} else if ($params['openid_mode'] == 'checkid_immediate') {
$ret = $this->_checkId($version, $params, 1, $extensions, $response);
if (is_bool($ret)) return $ret;
if (!empty($params['openid_return_to'])) {
Zend_OpenId::redirect($params['openid_return_to'], $ret, $response);
}
return true;
} else if ($params['openid_mode'] == 'checkid_setup') {
$ret = $this->_checkId($version, $params, 0, $extensions, $response);
if (is_bool($ret)) return $ret;
if (!empty($params['openid_return_to'])) {
Zend_OpenId::redirect($params['openid_return_to'], $ret, $response);
}
return true;
} else if ($params['openid_mode'] == 'check_authentication') {
$response = $this->_checkAuthentication($version, $params);
$ret = '';
foreach ($response as $key => $val) {
$ret .= $key . ':' . $val . "\n";
}
return $ret;
}
}
return false;
}
/**
* Generates a secret key for given hash function, returns RAW key or false
* if function is not supported
*
* @param string $func hash function (sha1 or sha256)
* @return mixed
*/
protected function _genSecret($func)
{
if ($func == 'sha1') {
$macLen = 20; /* 160 bit */
} else if ($func == 'sha256') {
$macLen = 32; /* 256 bit */
} else {
return false;
}
return Zend_OpenId::randomBytes($macLen);
}
/**
* Processes association request from OpenID consumerm generates secret
* shared key and send it back using Diffie-Hellman encruption.
* Returns array of variables to push back to consumer.
*
* @param float $version OpenID version
* @param array $params GET or POST request variables
* @return array
*/
protected function _associate($version, $params)
{
$ret = array();
if ($version >= 2.0) {
$ret['ns'] = Zend_OpenId::NS_2_0;
}
if (isset($params['openid_assoc_type']) &&
$params['openid_assoc_type'] == 'HMAC-SHA1') {
$macFunc = 'sha1';
} else if (isset($params['openid_assoc_type']) &&
$params['openid_assoc_type'] == 'HMAC-SHA256' &&
$version >= 2.0) {
$macFunc = 'sha256';
} else {
$ret['error'] = 'Wrong "openid.assoc_type"';
$ret['error-code'] = 'unsupported-type';
return $ret;
}
$ret['assoc_type'] = $params['openid_assoc_type'];
$secret = $this->_genSecret($macFunc);
if (empty($params['openid_session_type']) ||
$params['openid_session_type'] == 'no-encryption') {
$ret['mac_key'] = base64_encode($secret);
} else if (isset($params['openid_session_type']) &&
$params['openid_session_type'] == 'DH-SHA1') {
$dhFunc = 'sha1';
} else if (isset($params['openid_session_type']) &&
$params['openid_session_type'] == 'DH-SHA256' &&
$version >= 2.0) {
$dhFunc = 'sha256';
} else {
$ret['error'] = 'Wrong "openid.session_type"';
$ret['error-code'] = 'unsupported-type';
return $ret;
}
if (isset($params['openid_session_type'])) {
$ret['session_type'] = $params['openid_session_type'];
}
if (isset($dhFunc)) {
if (empty($params['openid_dh_consumer_public'])) {
$ret['error'] = 'Wrong "openid.dh_consumer_public"';
return $ret;
}
if (empty($params['openid_dh_gen'])) {
$g = pack('H*', Zend_OpenId::DH_G);
} else {
$g = base64_decode($params['openid_dh_gen']);
}
if (empty($params['openid_dh_modulus'])) {
$p = pack('H*', Zend_OpenId::DH_P);
} else {
$p = base64_decode($params['openid_dh_modulus']);
}
$dh = Zend_OpenId::createDhKey($p, $g);
$dh_details = Zend_OpenId::getDhKeyDetails($dh);
$sec = Zend_OpenId::computeDhSecret(
base64_decode($params['openid_dh_consumer_public']), $dh);
if ($sec === false) {
$ret['error'] = 'Wrong "openid.session_type"';
$ret['error-code'] = 'unsupported-type';
return $ret;
}
$sec = Zend_OpenId::digest($dhFunc, $sec);
$ret['dh_server_public'] = base64_encode(
Zend_OpenId::btwoc($dh_details['pub_key']));
$ret['enc_mac_key'] = base64_encode($secret ^ $sec);
}
$handle = uniqid();
$expiresIn = $this->_sessionTtl;
$ret['assoc_handle'] = $handle;
$ret['expires_in'] = $expiresIn;
$this->_storage->addAssociation($handle,
$macFunc, $secret, time() + $expiresIn);
return $ret;
}
/**
* Performs authentication (or authentication check).
*
* @param float $version OpenID version
* @param array $params GET or POST request variables
* @param bool $immediate enables or disables interaction with user
* @param mixed $extensions extension object or array of extensions objects
* @param Zend_Controller_Response_Abstract $response
* @return array
*/
protected function _checkId($version, $params, $immediate, $extensions=null,
Zend_Controller_Response_Abstract $response = null)
{
$ret = array();
if ($version >= 2.0) {
$ret['openid.ns'] = Zend_OpenId::NS_2_0;
}
$root = $this->getSiteRoot($params);
if ($root === false) {
return false;
}
if (isset($params['openid_identity']) &&
!$this->_storage->hasUser($params['openid_identity'])) {
$ret['openid.mode'] = ($immediate && $version >= 2.0) ? 'setup_needed': 'cancel';
return $ret;
}
/* Check if user already logged in into the server */
if (!isset($params['openid_identity']) ||
$this->_user->getLoggedInUser() !== $params['openid_identity']) {
$params2 = array();
foreach ($params as $key => $val) {
if (strpos($key, 'openid_ns_') === 0) {
$key = 'openid.ns.' . substr($key, strlen('openid_ns_'));
} else if (strpos($key, 'openid_sreg_') === 0) {
$key = 'openid.sreg.' . substr($key, strlen('openid_sreg_'));
} else if (strpos($key, 'openid_') === 0) {
$key = 'openid.' . substr($key, strlen('openid_'));
}
$params2[$key] = $val;
}
if ($immediate) {
$params2['openid.mode'] = 'checkid_setup';
$ret['openid.mode'] = ($version >= 2.0) ? 'setup_needed': 'id_res';
$ret['openid.user_setup_url'] = $this->_loginUrl
. (strpos($this->_loginUrl, '?') === false ? '?' : '&')
. Zend_OpenId::paramsToQuery($params2);
return $ret;
} else {
/* Redirect to Server Login Screen */
Zend_OpenId::redirect($this->_loginUrl, $params2, $response);
return true;
}
}
if (!Zend_OpenId_Extension::forAll($extensions, 'parseRequest', $params)) {
$ret['openid.mode'] = ($immediate && $version >= 2.0) ? 'setup_needed': 'cancel';
return $ret;
}
/* Check if user trusts to the consumer */
$trusted = null;
$sites = $this->_storage->getTrustedSites($params['openid_identity']);
if (isset($params['openid_return_to'])) {
$root = $params['openid_return_to'];
}
if (isset($sites[$root])) {
$trusted = $sites[$root];
} else {
foreach ($sites as $site => $t) {
if (strpos($root, $site) === 0) {
$trusted = $t;
break;
} else {
/* OpenID 2.0 (9.2) check for realm wild-card matching */
$n = strpos($site, '://*.');
if ($n != false) {
$regex = '/^'
. preg_quote(substr($site, 0, $n+3), '/')
. '[A-Za-z1-9_\.]+?'
. preg_quote(substr($site, $n+4), '/')
. '/';
if (preg_match($regex, $root)) {
$trusted = $t;
break;
}
}
}
}
}
if (is_array($trusted)) {
if (!Zend_OpenId_Extension::forAll($extensions, 'checkTrustData', $trusted)) {
$trusted = null;
}
}
if ($trusted === false) {
$ret['openid.mode'] = 'cancel';
return $ret;
} else if ($trusted === null) {
/* Redirect to Server Trust Screen */
$params2 = array();
foreach ($params as $key => $val) {
if (strpos($key, 'openid_ns_') === 0) {
$key = 'openid.ns.' . substr($key, strlen('openid_ns_'));
} else if (strpos($key, 'openid_sreg_') === 0) {
$key = 'openid.sreg.' . substr($key, strlen('openid_sreg_'));
} else if (strpos($key, 'openid_') === 0) {
$key = 'openid.' . substr($key, strlen('openid_'));
}
$params2[$key] = $val;
}
if ($immediate) {
$params2['openid.mode'] = 'checkid_setup';
$ret['openid.mode'] = ($version >= 2.0) ? 'setup_needed': 'id_res';
$ret['openid.user_setup_url'] = $this->_trustUrl
. (strpos($this->_trustUrl, '?') === false ? '?' : '&')
. Zend_OpenId::paramsToQuery($params2);
return $ret;
} else {
Zend_OpenId::redirect($this->_trustUrl, $params2, $response);
return true;
}
}
return $this->_respond($version, $ret, $params, $extensions);
}
/**
* Perepares information to send back to consumer's authentication request,
* signs it using shared secret and send back through HTTP redirection
*
* @param array $params GET or POST request variables
* @param mixed $extensions extension object or array of extensions objects
* @param Zend_Controller_Response_Abstract $response an optional response
* object to perform HTTP or HTML form redirection
* @return bool
*/
public function respondToConsumer($params, $extensions=null,
Zend_Controller_Response_Abstract $response = null)
{
$version = 1.1;
if (isset($params['openid_ns']) &&
$params['openid_ns'] == Zend_OpenId::NS_2_0) {
$version = 2.0;
}
$ret = array();
if ($version >= 2.0) {
$ret['openid.ns'] = Zend_OpenId::NS_2_0;
}
$ret = $this->_respond($version, $ret, $params, $extensions);
if (!empty($params['openid_return_to'])) {
Zend_OpenId::redirect($params['openid_return_to'], $ret, $response);
}
return true;
}
/**
* Perepares information to send back to consumer's authentication request
* and signs it using shared secret.
*
* @param float $version OpenID protcol version
* @param array $ret arguments to be send back to consumer
* @param array $params GET or POST request variables
* @param mixed $extensions extension object or array of extensions objects
* @return array
*/
protected function _respond($version, $ret, $params, $extensions=null)
{
if (empty($params['openid_assoc_handle']) ||
!$this->_storage->getAssociation($params['openid_assoc_handle'],
$macFunc, $secret, $expires)) {
/* Use dumb mode */
if (!empty($params['openid_assoc_handle'])) {
$ret['openid.invalidate_handle'] = $params['openid_assoc_handle'];
}
$macFunc = $version >= 2.0 ? 'sha256' : 'sha1';
$secret = $this->_genSecret($macFunc);
$handle = uniqid();
$expiresIn = $this->_sessionTtl;
$this->_storage->addAssociation($handle,
$macFunc, $secret, time() + $expiresIn);
$ret['openid.assoc_handle'] = $handle;
} else {
$ret['openid.assoc_handle'] = $params['openid_assoc_handle'];
}
if (isset($params['openid_return_to'])) {
$ret['openid.return_to'] = $params['openid_return_to'];
}
if (isset($params['openid_claimed_id'])) {
$ret['openid.claimed_id'] = $params['openid_claimed_id'];
}
if (isset($params['openid_identity'])) {
$ret['openid.identity'] = $params['openid_identity'];
}
if ($version >= 2.0) {
if (!empty($this->_opEndpoint)) {
$ret['openid.op_endpoint'] = $this->_opEndpoint;
} else {
$ret['openid.op_endpoint'] = Zend_OpenId::selfUrl();
}
}
$ret['openid.response_nonce'] = gmdate('Y-m-d\TH:i:s\Z') . uniqid();
$ret['openid.mode'] = 'id_res';
Zend_OpenId_Extension::forAll($extensions, 'prepareResponse', $ret);
$signed = '';
$data = '';
foreach ($ret as $key => $val) {
if (strpos($key, 'openid.') === 0) {
$key = substr($key, strlen('openid.'));
if (!empty($signed)) {
$signed .= ',';
}
$signed .= $key;
$data .= $key . ':' . $val . "\n";
}
}
$signed .= ',signed';
$data .= 'signed:' . $signed . "\n";
$ret['openid.signed'] = $signed;
$ret['openid.sig'] = base64_encode(
Zend_OpenId::hashHmac($macFunc, $data, $secret));
return $ret;
}
/**
* Performs authentication validation for dumb consumers
* Returns array of variables to push back to consumer.
* It MUST contain 'is_valid' variable with value 'true' or 'false'.
*
* @param float $version OpenID version
* @param array $params GET or POST request variables
* @return array
*/
protected function _checkAuthentication($version, $params)
{
$ret = array();
if ($version >= 2.0) {
$ret['ns'] = Zend_OpenId::NS_2_0;
}
$ret['openid.mode'] = 'id_res';
if (empty($params['openid_assoc_handle']) ||
empty($params['openid_signed']) ||
empty($params['openid_sig']) ||
!$this->_storage->getAssociation($params['openid_assoc_handle'],
$macFunc, $secret, $expires)) {
$ret['is_valid'] = 'false';
return $ret;
}
$signed = explode(',', $params['openid_signed']);
$data = '';
foreach ($signed as $key) {
$data .= $key . ':';
if ($key == 'mode') {
$data .= "id_res\n";
} else {
$data .= $params['openid_' . strtr($key,'.','_')]."\n";
}
}
if (base64_decode($params['openid_sig']) ===
Zend_OpenId::hashHmac($macFunc, $data, $secret)) {
$ret['is_valid'] = 'true';
} else {
$ret['is_valid'] = 'false';
}
return $ret;
}
}

View file

@ -0,0 +1,106 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Storage.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* Abstract class to implement external storage for OpenID consumer
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_OpenId_Provider_Storage
{
/**
* Stores information about session identified by $handle
*
* @param string $handle assiciation handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param string $expires expiration UNIX time
* @return void
*/
abstract public function addAssociation($handle, $macFunc, $secret, $expires);
/**
* Gets information about association identified by $handle
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $handle assiciation handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param string &$expires expiration UNIX time
* @return bool
*/
abstract public function getAssociation($handle, &$macFunc, &$secret, &$expires);
/**
* Register new user with given $id and $password
* Returns true in case of success and false if user with given $id already
* exists
*
* @param string $id user identity URL
* @param string $password encoded user password
* @return bool
*/
abstract public function addUser($id, $password);
/**
* Returns true if user with given $id exists and false otherwise
*
* @param string $id user identity URL
* @return bool
*/
abstract public function hasUser($id);
/**
* Verify if user with given $id exists and has specified $password
*
* @param string $id user identity URL
* @param string $password user password
* @return bool
*/
abstract public function checkUser($id, $password);
/**
* Returns array of all trusted/untrusted sites for given user identified
* by $id
*
* @param string $id user identity URL
* @return array
*/
abstract public function getTrustedSites($id);
/**
* Stores information about trusted/untrusted site for given user
*
* @param string $id user identity URL
* @param string $site site URL
* @param mixed $trusted trust data from extensions or just a boolean value
* @return bool
*/
abstract public function addSite($id, $site, $trusted);
}

View file

@ -0,0 +1,442 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: File.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_OpenId_Provider_Storage
*/
require_once "Zend/OpenId/Provider/Storage.php";
/**
* External storage implemmentation using serialized files
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Provider_Storage_File extends Zend_OpenId_Provider_Storage
{
/**
* Directory name to store data files in
*
* @var string $_dir
*/
private $_dir;
/**
* Constructs storage object and creates storage directory
*
* @param string $dir directory name to store data files in
* @throws Zend_OpenId_Exception
*/
public function __construct($dir = null)
{
if ($dir === null) {
$tmp = getenv('TMP');
if (empty($tmp)) {
$tmp = getenv('TEMP');
if (empty($tmp)) {
$tmp = "/tmp";
}
}
$user = get_current_user();
if (is_string($user) && !empty($user)) {
$tmp .= '/' . $user;
}
$dir = $tmp . '/openid/provider';
}
$this->_dir = $dir;
if (!is_dir($this->_dir)) {
if (!@mkdir($this->_dir, 0700, 1)) {
throw new Zend_OpenId_Exception(
"Cannot access storage directory $dir",
Zend_OpenId_Exception::ERROR_STORAGE);
}
}
if (($f = fopen($this->_dir.'/assoc.lock', 'w+')) === null) {
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
fclose($f);
if (($f = fopen($this->_dir.'/user.lock', 'w+')) === null) {
throw new Zend_OpenId_Exception(
'Cannot create a lock file in the directory ' . $dir,
Zend_OpenId_Exception::ERROR_STORAGE);
}
fclose($f);
}
/**
* Stores information about session identified by $handle
*
* @param string $handle assiciation handle
* @param string $macFunc HMAC function (sha1 or sha256)
* @param string $secret shared secret
* @param string $expires expiration UNIX time
* @return bool
*/
public function addAssociation($handle, $macFunc, $secret, $expires)
{
$name = $this->_dir . '/assoc_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'w+');
if ($f === false) {
fclose($lock);
return false;
}
$data = serialize(array($handle, $macFunc, $secret, $expires));
fwrite($f, $data);
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Gets information about association identified by $handle
* Returns true if given association found and not expired and false
* otherwise
*
* @param string $handle assiciation handle
* @param string &$macFunc HMAC function (sha1 or sha256)
* @param string &$secret shared secret
* @param string &$expires expiration UNIX time
* @return bool
*/
public function getAssociation($handle, &$macFunc, &$secret, &$expires)
{
$name = $this->_dir . '/assoc_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedHandle, $macFunc, $secret, $expires) = unserialize($data);
if ($handle === $storedHandle && $expires > time()) {
$ret = true;
} else {
fclose($f);
@unlink($name);
fclose($lock);
return false;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Removes information about association identified by $handle
*
* @param string $handle assiciation handle
* @return bool
*/
public function delAssociation($handle)
{
$name = $this->_dir . '/assoc_' . md5($handle);
$lock = @fopen($this->_dir . '/assoc.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
@unlink($name);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Register new user with given $id and $password
* Returns true in case of success and false if user with given $id already
* exists
*
* @param string $id user identity URL
* @param string $password encoded user password
* @return bool
*/
public function addUser($id, $password)
{
$name = $this->_dir . '/user_' . md5($id);
$lock = @fopen($this->_dir . '/user.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'x');
if ($f === false) {
fclose($lock);
return false;
}
$data = serialize(array($id, $password, array()));
fwrite($f, $data);
fclose($f);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Returns true if user with given $id exists and false otherwise
*
* @param string $id user identity URL
* @return bool
*/
public function hasUser($id)
{
$name = $this->_dir . '/user_' . md5($id);
$lock = @fopen($this->_dir . '/user.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_SH)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedId, $storedPassword, $trusted) = unserialize($data);
if ($id === $storedId) {
$ret = true;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Verify if user with given $id exists and has specified $password
*
* @param string $id user identity URL
* @param string $password user password
* @return bool
*/
public function checkUser($id, $password)
{
$name = $this->_dir . '/user_' . md5($id);
$lock = @fopen($this->_dir . '/user.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_SH)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedId, $storedPassword, $trusted) = unserialize($data);
if ($id === $storedId && $password === $storedPassword) {
$ret = true;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Removes information abou specified user
*
* @param string $id user identity URL
* @return bool
*/
public function delUser($id)
{
$name = $this->_dir . '/user_' . md5($id);
$lock = @fopen($this->_dir . '/user.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
@unlink($name);
fclose($lock);
return true;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Returns array of all trusted/untrusted sites for given user identified
* by $id
*
* @param string $id user identity URL
* @return array
*/
public function getTrustedSites($id)
{
$name = $this->_dir . '/user_' . md5($id);
$lock = @fopen($this->_dir . '/user.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_SH)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedId, $storedPassword, $trusted) = unserialize($data);
if ($id === $storedId) {
$ret = $trusted;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
/**
* Stores information about trusted/untrusted site for given user
*
* @param string $id user identity URL
* @param string $site site URL
* @param mixed $trusted trust data from extension or just a boolean value
* @return bool
*/
public function addSite($id, $site, $trusted)
{
$name = $this->_dir . '/user_' . md5($id);
$lock = @fopen($this->_dir . '/user.lock', 'w+');
if ($lock === false) {
return false;
}
if (!flock($lock, LOCK_EX)) {
fclose($lock);
return false;
}
try {
$f = @fopen($name, 'r+');
if ($f === false) {
fclose($lock);
return false;
}
$ret = false;
$data = stream_get_contents($f);
if (!empty($data)) {
list($storedId, $storedPassword, $sites) = unserialize($data);
if ($id === $storedId) {
if ($trusted === null) {
unset($sites[$site]);
} else {
$sites[$site] = $trusted;
}
rewind($f);
ftruncate($f, 0);
$data = serialize(array($id, $storedPassword, $sites));
fwrite($f, $data);
$ret = true;
}
}
fclose($f);
fclose($lock);
return $ret;
} catch (Exception $e) {
fclose($lock);
throw $e;
}
}
}

View file

@ -0,0 +1,57 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: User.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* Abstract class to get/store information about logged in user in Web Browser
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
abstract class Zend_OpenId_Provider_User
{
/**
* Stores information about logged in user
*
* @param string $id user identity URL
* @return bool
*/
abstract public function setLoggedInUser($id);
/**
* Returns identity URL of logged in user or false
*
* @return mixed
*/
abstract public function getLoggedInUser();
/**
* Performs logout. Clears information about logged in user.
*
* @return bool
*/
abstract public function delLoggedInUser();
}

View file

@ -0,0 +1,104 @@
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Session.php 20096 2010-01-06 02:05:09Z bkarwin $
*/
/**
* @see Zend_OpenId_Provider_User
*/
require_once "Zend/OpenId/Provider/User.php";
/**
* @see Zend_Session_Namespace
*/
require_once "Zend/Session/Namespace.php";
/**
* Class to get/store information about logged in user in Web Browser using
* PHP session
*
* @category Zend
* @package Zend_OpenId
* @subpackage Zend_OpenId_Provider
* @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_OpenId_Provider_User_Session extends Zend_OpenId_Provider_User
{
/**
* Reference to an implementation of Zend_Session_Namespace object
*
* @var Zend_Session_Namespace $_session
*/
private $_session = null;
/**
* Creates Zend_OpenId_Provider_User_Session object with given session
* namespace or creates new session namespace named "openid"
*
* @param Zend_Session_Namespace $session
*/
public function __construct(Zend_Session_Namespace $session = null)
{
if ($session === null) {
$this->_session = new Zend_Session_Namespace("openid");
} else {
$this->_session = $session;
}
}
/**
* Stores information about logged in user in session data
*
* @param string $id user identity URL
* @return bool
*/
public function setLoggedInUser($id)
{
$this->_session->logged_in = $id;
return true;
}
/**
* Returns identity URL of logged in user or false
*
* @return mixed
*/
public function getLoggedInUser()
{
if (isset($this->_session->logged_in)) {
return $this->_session->logged_in;
}
return false;
}
/**
* Performs logout. Clears information about logged in user.
*
* @return bool
*/
public function delLoggedInUser()
{
unset($this->_session->logged_in);
return true;
}
}