Commit ff20537f authored by lphuberdeau's avatar lphuberdeau

[NEW] Grant higher privileges using a token for a single request

parent bc7d8340
......@@ -1341,6 +1341,7 @@ lib/ajax/tiki-ajax.js -text
lib/articles/artlib.php -text
lib/articles/index.php -text
lib/auth/ldap.php -text
lib/auth/tokens.php -text
lib/bablotron.php -text
lib/ban/banlib.php -text
lib/ban/index.php -text
......@@ -2464,6 +2465,8 @@ lib/test/README -text
lib/test/TikiAcceptanceTestDBRestorer.php -text
lib/test/TikiSeleniumTestCase.php -text
lib/test/TikiTestCase.php -text
lib/test/auth/AuthTokensTest.php -text
lib/test/bootstrap.php -text
lib/test/core/Category/ManipulatorTest.php -text
lib/test/core/DeclFilter/BaseTest.php -text
lib/test/core/DeclFilter/CatchAllFilterTest.php -text
......@@ -2530,6 +2533,7 @@ lib/test/importer/tikiimporter_testcase.php -text
lib/test/importer/tikiimporter_wiki_mediawiki_test.php -text
lib/test/importer/tikiimporter_wiki_test.php -text
lib/test/index.php -text
lib/test/phpunit.xml -text
lib/themecontrol/index.php -text
lib/themecontrol/tcontrol.php -text
lib/tiki-dynamic-js.php -text
......
<?php
class AuthTokens
{
const SCHEME = 'MD5( CONCAT(tokenId, creation, timeout, entry, parameters, groups) )';
private $db;
private $maxTimeout;
public static function build( $prefs ) {
return new AuthTokens( TikiDb::get(), array(
'maxTimeout' => $prefs['auth_token_access_maxtimeout'],
) );
}
function __construct( $db, $options = array() ) {
$this->db = $db;
if( isset( $options['maxTimeout'] ) ) {
$this->maxTimeout = (int) $options['maxTimeout'];
}
}
function getGroups( $token, $entry, $parameters ) {
$this->db->query( 'DELETE FROM tiki_auth_tokens WHERE creation + timeout < NOW()' );
$data = $this->db->query( 'SELECT entry, parameters, groups FROM tiki_auth_tokens WHERE token = ? AND token = ' . self::SCHEME, array( $token ) )
->fetchRow();
if( $data['entry'] != $entry ) {
return null;
}
$registered = json_decode( $data['parameters'], true );
if( ! $this->allPresent( $registered, $parameters )
|| ! $this->allPresent( $parameters, $registered ) ) {
return null;
}
return json_decode( $data['groups'], true );
}
private function allPresent( $a, $b ) {
foreach( $a as $key => $value ) {
if( ! isset($b[$key]) || $value != $b[$key] ) {
return false;
}
}
return true;
}
function createToken( $entry, array $parameters, array $groups, $timeout = 3600 ) {
if( ! is_null( $this->maxTimeout ) ) {
$timeout = min( $this->maxTimeout, $timeout );
}
$this->db->query( 'INSERT INTO tiki_auth_tokens ( timeout, entry, parameters, groups ) VALUES( ?, ?, ?, ? )', array(
(int) $timeout,
$entry,
json_encode( $parameters ),
json_encode( $groups ),
) );
$max = $this->db->getOne( 'SELECT MAX(tokenId) FROM tiki_auth_tokens' );
$this->db->query( 'UPDATE tiki_auth_tokens SET token = ' . self::SCHEME . ' WHERE tokenId = ?', array( $max ) );
return $this->db->getOne( 'SELECT token FROM tiki_auth_tokens WHERE tokenId = ?', array( $max ) );
}
}
?>
......@@ -17,5 +17,17 @@ function prefs_auth_list() {
'ws' => tra('Web Server'),
),
),
'auth_token_access' => array(
'name' => tra('Token Access'),
'description' => tra('Allow to access the content with superior rights with the presentation of a token. The primary use of this authentication method is to grant temporary access to content to an external service.'),
'type' => 'flag',
),
'auth_token_access_maxtimeout' => array(
'name' => tra('Token Access Max Timeout'),
'description' => tra('The maximum duration for which the generated tokens will be valid.'),
'type' => 'text',
'size' => 5,
'filter' => 'digits',
),
);
}
......@@ -50,6 +50,17 @@ foreach( $allperms['data'] as $row ) {
$groupList = $tikilib->get_user_groups( $user );
if( $prefs['auth_token_access'] == 'y' && isset($_REQUEST['TOKEN']) ) {
require_once 'lib/auth/tokens.php';
$token = $_REQUEST['TOKEN'];
unset( $_REQUEST['TOKEN'] );
$tokenlib = AuthTokens::build( $prefs );
if( $groups = $tokenlib->getGroups( $token, $_SERVER['PHP_SELF'], $_REQUEST ) ) {
$groupList = $groups;
}
}
require_once 'lib/core/lib/Perms.php';
require_once 'lib/core/lib/Perms/Check/Direct.php';
require_once 'lib/core/lib/Perms/Check/Indirect.php';
......
......@@ -1500,6 +1500,10 @@ function get_default_prefs() {
'feature_use_minified_scripts' => 'y', // for debugging
'tiki_minify_javascript' => 'n',
// Token Access
'auth_token_access' => 'n',
'auth_token_access_maxtimeout' => 30,
);
// spellcheck
......
<?php
require_once 'lib/auth/tokens.php';
class AuthTokensTest extends PHPUnit_Framework_TestCase
{
private $db;
function setUp() {
$this->db = TikiDb::get();
$this->db->query( 'TRUNCATE tiki_auth_tokens' );
}
function tearDown() {
$this->db->query( 'TRUNCATE tiki_auth_tokens' );
}
function testNoTokensIsDenied() {
$lib = new AuthTokens( $this->db );
$params = array();
$groups = $lib->getGroups( 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'tiki-index.php', $params );
$this->assertNull( $groups );
}
function testCreateToken() {
$lib = new AuthTokens( $this->db );
$data = array(
'tokenId' => 1,
'timeout' => 5,
'entry' => 'tiki-index.php',
'parameters' => '{"page":"HomePage"}',
'groups' => '["Registered"]',
);
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$this->assertEquals( $data, $this->db->query( 'SELECT tokenId, timeout, entry, parameters, groups FROM tiki_auth_tokens' )->fetchRow() );
$this->assertEquals( 32, strlen( $token ) );
}
function testTokenMatchesCompleteHash() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$row = $this->db->query( 'SELECT tokenId, creation, timeout, entry, parameters, groups FROM tiki_auth_tokens' )->fetchRow();
$this->assertEquals( md5( implode('', $row) ), $token );
}
function testRetrieveGroupsForToken() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$this->assertEquals( array( 'Registered' ), $lib->getGroups( $token, 'tiki-index.php', array('page' => 'HomePage') ) );
}
function testAccessExpiredToken() {
$lib = new AuthTokens( $this->db );
$this->db->query( 'INSERT INTO tiki_auth_tokens (tokenId, creation, timeout, entry, parameters, groups, token) VALUES(?, ?, ?, ?, ?, ?, ?)', array( 1, '2009-11-05 11:45:16', 5, 'tiki-index.php', '{"page":"HomePage"}', '["Registered"]', "946fc2fa0a5e1cecd54440ce733b8fb4" ) );
$this->assertNull( $lib->getGroups( "946fc2fa0a5e1cecd54440ce733b8fb4", 'tiki-index.php', array( 'page' => 'HomePage' ) ) );
}
function testAlteredDataCancels() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$this->db->query( 'UPDATE tiki_auth_tokens SET groups = \'["Admins"]\'' );
$this->assertNull( $lib->getGroups( $token, 'tiki-index.php', array('page' => 'HomePage') ) );
}
function testExtraDataCancels() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$this->assertNull( $lib->getGroups( $token, 'tiki-index.php', array('page' => 'HomePage', 'hello' => 'world') ) );
}
function testMissingDataCancels() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage', 'foobar' => 'baz'), array( 'Registered' ), 5 );
$this->assertNull( $lib->getGroups( $token, 'tiki-index.php', array('page' => 'HomePage') ) );
}
function testDifferingEntryCancels() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$this->assertNull( $lib->getGroups( $token, 'tiki-print.php', array('page' => 'HomePage') ) );
}
function testDifferingValueCancels() {
$lib = new AuthTokens( $this->db );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 5 );
$this->assertNull( $lib->getGroups( $token, 'tiki-index.php', array('page' => 'Home') ) );
}
function testMaximumTimeout() {
$lib = new AuthTokens( $this->db, array(
'maxTimeout' => 10,
) );
$token = $lib->createToken( 'tiki-index.php', array('page' => 'HomePage'), array( 'Registered' ), 3600 );
$this->assertEquals( 10, $this->db->getOne( 'SELECT timeout FROM tiki_auth_tokens WHERE tokenId = 1' ) );
}
}
<?php
require_once(dirname(__FILE__) . '/TikiTestCase.php');
ini_set( 'display_errors', 'on' );
error_reporting( E_ALL );
ini_set( 'include_path', ini_get('include_path') . PATH_SEPARATOR . "." . PATH_SEPARATOR . "../core/lib" . PATH_SEPARATOR . "../.." );
function tra( $string ) {
return $string;
}
function __autoload( $name ) {
$path = str_replace( '_', '/', $name );
require_once( $path . '.php' );
}
$api_tiki = null;
require 'db/local.php';
if (extension_loaded("pdo") and $api_tiki == 'pdo' ) {
require_once('db/tiki-db-pdo.php');
} else {
require_once('db/tiki-db-adodb.php');
}
$db = TikiDb::get();
$db->setServerType( $db_tiki );
$pwd = getcwd();
chdir('../../');
require_once 'lib/cache/cachelib.php';
chdir($pwd);
<phpunit bootstrap="bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="false">
</phpunit>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment