Skip to content

Commit

Permalink
namespace re-org, bug if missing cookie
Browse files Browse the repository at this point in the history
  • Loading branch information
mrclay committed Jun 22, 2011
1 parent 531f269 commit d86a8ae
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 127 deletions.
11 changes: 0 additions & 11 deletions src/Shibalike/Attr/ICondition.php

This file was deleted.

4 changes: 2 additions & 2 deletions src/Shibalike/Attr/IStore.php
@@ -1,8 +1,8 @@
<?php

namespace Shibalike;
namespace Shibalike\Attr;

interface Attr_IStore {
interface IStore {

/**
* Return "shibboleth" attributes for a user
Expand Down
@@ -1,8 +1,10 @@
<?php

namespace Shibalike;
namespace Shibalike\Attr\Store;

class Attr_Store_Array implements \Shibalike\Attr_IStore {
use Shibalike\Attr\IStore;

class ArrayStore implements IStore {
protected $_storage = array();

public function __construct(array $source) {
Expand Down
6 changes: 4 additions & 2 deletions src/Shibalike/Attr/Store/ZendDb.php
@@ -1,8 +1,10 @@
<?php

namespace Shibalike;
namespace Shibalike\Attr\Store;

class Attr_Store_ZendDb implements \Shibalike\Attr_IStore {
use Shibalike\Attr\IStore;

class ZendDb implements IStore {
/**
* @var \Zend_Db_Adapter_Abstract
*/
Expand Down
10 changes: 5 additions & 5 deletions src/Shibalike/StateManager/UserlandSession.php
@@ -1,18 +1,18 @@
<?php

namespace Shibalike;
namespace Shibalike\StateManager;

use Util_UserlandSession as Sess;
use Shibalike\IStateManager;

class StateManager_UserlandSession implements IStateManager {
class UserlandSession implements IStateManager {

/**
* @var \Shibalike\Util_UserlandSession
* @var \Shibalike\Util\UserlandSession
*/
protected $_session;

/**
* @param \Shibalike\Util_UserlandSession $session
* @param \Shibalike\Util\UserlandSession $session
*/
public function __construct(Sess $session)
{
Expand Down
71 changes: 71 additions & 0 deletions src/Shibalike/Util/IdGenerator.php
@@ -0,0 +1,71 @@
<?php

namespace Shibalike\Util;

class IdGenerator {

/**
* Create a random alphanumeric string
*
* @param int $length
* @return string
*/
public static function generateBase32Id($length = 40)
{
// generate random bytes, more than we need (adapted from phpass)
$numBytes = $length;
$randomState = microtime();
if (function_exists('getmypid')) {
$randomState .= getmypid();
}
$bytes = '';
if (@is_readable('/dev/urandom') && ($fh = @fopen('/dev/urandom', 'rb'))) {
$bytes = fread($fh, $numBytes);
fclose($fh);
}
if (strlen($bytes) < $numBytes) {
$bytes = '';
for ($i = 0; $i < $numBytes; $i += 16) {
$randomState = md5(microtime() . $randomState . mt_rand(0, mt_getrandmax()));
$bytes .= pack('H*', md5($randomState));
}
$bytes = substr($bytes, 0, $numBytes);
}
// convert bytes to base36, strip non-alphanumerics), return a random chunk
return substr(self::_bin_to_base32($bytes), 0, $length);
}

/**
* Convert binary input to base32 (lossy for speed purposes, not a reversible operation).
*
* @link http://inquisitivecocoa.com/2009/08/10/a-basic-base32_encode-function-for-php/
* @param string $bytes
* @return string
* @license unknown
*/
static protected function _bin_to_base32($bytes) {
$hex = unpack('H*', $bytes);
$hex = $hex[1];
$binary = '';
for ($i = 0, $l = strlen($hex); $i < $l; $i++) {
$binary .= decbin(hexdec($hex[$i]));
}

$binaryLength = strlen($binary);
$base32_characters = "0123456789abcdefghijklmnopqrstuv";
$currentPosition = 0;
$output = '';

while ($currentPosition < $binaryLength) {
$bits = substr($binary, $currentPosition, 5);
// don't worry about padding last 5-bit number

// Convert the 5 bits into a decimal number
// and append the matching character to $output
$output .= $base32_characters[bindec($bits)];
$currentPosition += 5;
}
// don't bother padding
return $output;
}
}
100 changes: 22 additions & 78 deletions src/Shibalike/Util/UserlandSession.php
@@ -1,6 +1,12 @@
<?php

namespace Shibalike;
namespace Shibalike\Util;

use Shibalike\Util\UserlandSession\IStorage;

use Shibalike\Util\IdGenerator;

use Shibalike\Util\UserlandSession\Storage\Files;

/**
* A PHP emulation of native session behavior. Other than HTTP IO (header() and
Expand All @@ -21,7 +27,7 @@
*
* Also a tiny session fixation vulnerability has been prevented in start().
*/
class Util_UserlandSession {
class UserlandSession {

const CACHE_LIMITER_NONE = '';
const CACHE_LIMITER_PUBLIC = 'public';
Expand All @@ -37,6 +43,7 @@ class Util_UserlandSession {
public $gc_maxlifetime = 1400;
public $gc_probability = 1;
public $gc_divisor = 100;
public $id_length = 40;
public $cache_limiter = self::CACHE_LIMITER_NOCACHE;
public $cache_expire = 180;

Expand All @@ -48,7 +55,7 @@ class Util_UserlandSession {
public $data = null;

/**
* @return Util_UserlandSession_IStorage
* @return Shibalike\Util\UserlandSession\IStorage
*/
public function get_storage()
{
Expand All @@ -59,9 +66,9 @@ public function get_storage()
/**
* Users should consider using factory() to prevent cookie/storage name collisions.
*
* @param Util_UserlandSession_IStorage $storage
* @param Shibalike\Util\UserlandSession\IStorage $storage
*/
public function __construct(Util_UserlandSession_IStorage $storage)
public function __construct(IStorage $storage)
{
$this->_storage = $storage;
$this->_name = $storage->getName();
Expand All @@ -75,16 +82,16 @@ public function __construct(Util_UserlandSession_IStorage $storage)
* names that are unique (case-insentively) to avoid creating cookie/storage
* collisions. It also forbids using a name that matches the global setting session.name.
*
* @param Util_UserlandSession_IStorage $storage (will use Files if not specified)
* @return Util_UserlandSession
* @param Shibalike\Util\UserlandSession\IStorage $storage (will use Files if not specified)
* @return Shibalike\Util\UserlandSession
*/
public static function factory(Util_UserlandSession_IStorage $storage = null)
public static function factory(IStorage $storage = null)
{
static $activeNames = array();
static $i = 1;

if (null === $storage) {
$storage = new \Shibalike\Util_UserlandSession_Storage_Files("SHIBALIKE$i");
$storage = new Files("SHIBALIKE$i");
$i++;
}
$activeNames[strtoupper(ini_get('session.name'))] = true;
Expand Down Expand Up @@ -174,9 +181,9 @@ public function start()
$this->_requestedId = null;
} else {
$id = $this->get_id_from_cookie();
if ($id) {
$this->_id = $id;
}
$this->_id = $id
? $id
: IdGenerator::generateBase32Id($this->id_length);
}
// should we call GC?
$rand = mt_rand(1, $this->gc_divisor);
Expand All @@ -187,11 +194,11 @@ public function start()
$this->_storage->open();

// try data fetch
if (! $this->_load_data()) {
if (! $this->_load_data()) {
// unlike the native PHP session, we don't let users choose their own
// session IDs if there's no data. This prevents session fixation through
// cookies (very hard for an attacker, but why leave this door open?).
$this->_id = self::generate_new_id();
$this->_id = IdGenerator::generateBase32Id($this->id_length);
$this->_set_cookie($this->_name, $this->_id);
}
// send optional cache limiter
Expand Down Expand Up @@ -283,7 +290,7 @@ public function regenerate_id($delete_old_session = false)
}
$this->remove_cookie();
$oldId = $this->_id;
$this->_id = self::generate_new_id();
$this->_id = IdGenerator::generateBase32Id($this->id_length);
$this->_set_cookie($this->_name, $this->_id);
if ($oldId && $delete_old_session) {
$this->_storage->destroy($oldId);
Expand All @@ -301,69 +308,6 @@ public function remove_cookie()
return setcookie($this->_name, '', time() - 86400, $this->cookie_path, $this->cookie_domain, (bool) $this->cookie_secure, (bool) $this->cookie_httponly);
}

/**
* Create a random alphanumeric string
*
* @param int $length
* @return string
*/
public static function generate_new_id($length = 40)
{
// generate random bytes, more than we need (adapted from phpass)
$numBytes = $length;
$randomState = microtime();
if (function_exists('getmypid')) {
$randomState .= getmypid();
}
$bytes = '';
if (@is_readable('/dev/urandom') && ($fh = @fopen('/dev/urandom', 'rb'))) {
$bytes = fread($fh, $numBytes);
fclose($fh);
}
if (strlen($bytes) < $numBytes) {
$bytes = '';
for ($i = 0; $i < $numBytes; $i += 16) {
$randomState = md5(microtime() . $randomState . mt_rand(0, mt_getrandmax()));
$bytes .= pack('H*', md5($randomState));
}
$bytes = substr($bytes, 0, $numBytes);
}
// convert bytes to base36, strip non-alphanumerics), return a random chunk
return substr(self::_bin_to_base32($bytes), 0, $length);
}

/**
* @link http://inquisitivecocoa.com/2009/08/10/a-basic-base32_encode-function-for-php/
* @param string $bytes
* @return string
* @license unknown
*/
static protected function _bin_to_base32($bytes) {
$hex = unpack('H*', $bytes);
$hex = $hex[1];
$binary = '';
for ($i = 0, $l = strlen($hex); $i < $l; $i++) {
$binary .= decbin(hexdec($hex[$i]));
}

$binaryLength = strlen($binary);
$base32_characters = "0123456789abcdefghijklmnopqrstuv";
$currentPosition = 0;
$output = '';

while ($currentPosition < $binaryLength) {
$bits = substr($binary, $currentPosition, 5);
// don't worry about padding last 5-bit number

// Convert the 5 bits into a decimal number
// and append the matching character to $output
$output .= $base32_characters[bindec($bits)];
$currentPosition += 5;
}
// don't bother padding
return $output;
}

/**
* Get a GMT formatted date for use in HTTP headers
*
Expand Down
4 changes: 2 additions & 2 deletions src/Shibalike/Util/UserlandSession/IStorage.php
@@ -1,8 +1,8 @@
<?php

namespace Shibalike;
namespace Shibalike\Util\UserlandSession;

interface Util_UserlandSession_IStorage {
interface IStorage {

/**
* @param string $name session name (to be used in cookie)
Expand Down
6 changes: 4 additions & 2 deletions src/Shibalike/Util/UserlandSession/Storage/Files.php
@@ -1,11 +1,13 @@
<?php

namespace Shibalike;
namespace Shibalike\Util\UserlandSession\Storage;

use Shibalike\Util\UserlandSession\IStorage;

/**
* File session storage.
*/
class Util_UserlandSession_Storage_Files implements Util_UserlandSession_IStorage {
class Files implements IStorage {

/**
* @param string $name session name (to be used in cookie)
Expand Down
4 changes: 2 additions & 2 deletions tests/UserlandSession/generate_new_id.php
@@ -1,5 +1,5 @@
<?php

require __DIR__ . '/../../src/Shibalike/Util/UserlandSession.php';
require __DIR__ . '/../../src/Shibalike/Util/IdGenerator.php';

echo Shibalike\Util_UserlandSession::generate_new_id();
echo Shibalike\Util\IdGenerator::generateBase32Id();

0 comments on commit d86a8ae

Please sign in to comment.