Merge branch 'dev' of https://github.com/redmatrix/hubzilla into dev_merge

This commit is contained in:
zotlabs 2017-12-21 13:36:33 -08:00
commit e7143a265a
388 changed files with 18999 additions and 13488 deletions

114
CHANGELOG
View File

@ -1,3 +1,117 @@
Hubzilla 3.0 (????-??-??)
- Don't zidify all permalinks, only zot permalinks
- Make remote homelink link to the home host and not to the home channel
- Auto promote beginner (techlevel 0) accounts to level 1 after they show signs of active participation.
- Go back to including the photo thumbnail data in the export file.
- Improvements to file import/export
- Default value for xlink_rating_text
- Implement IMoveTarget and recursive file/directory move/rename - github issue #680
- Synchronise an attach_move operation to clones
- Provide a themed page with an error notification on errors instead of an obtuse XML error structure in mod cloud
- Disallow backslashes in wiki and wiki-page names
- We only require one update module. The rest are superfluous.
- Render installable elements as buttons instead of links
- Implement chunked uploads for photos page
- Remove warning for large files on cloud upload
- Add a filter for notification to show new posts only
- Implement chunked uploads for cloud
- Use httpsig auth for getfile
- Load the profile images in the custom acl selector only if we actually need them
- Rework liveUpdate() and notificationsUpdate() (aka ping) to first do the liveUpdate and when this is done only do the ping once.
- Don't include invisible "update activities" in category widget
- Default profile assign
- Provide system config option for minimum registration age.
- Remove deprecated $a argument from advanced_profile()
- Change to bbcode calling parameters
- Extra checking of server headers in upload functions
- Provide a handler for chunked uploads in mod file_upload
- Optional divider between item header and body
- Allow toggle to SMBC scaling mode.
- Add thumbnail hook
- Implement SVG thumbnails and expose security setting
- Implement video thumbnail generator
- Implement pdf thumbnails
- Implement thumbnail generator for epubs
- Make browser history buttons work with ajax calls in mod display and hq
- Implement tile view for mod cloud (read only)
- Add mp3 audio thumbnail generator
- Set display_path for photo_upload from the DAV File interface
- Provide a generalised interface for thumbnail generators to support various content types
- Add ID3Parser library.
- Text thumbnails in cloud tile mode
- Revisit media breakpoints - do not switch to mobile view to early.
- Add French to help pages language dropdown selector
- Inroduce the HQ module - an alternative landing page for hubzilla
- Strip author name from notify messages in notifications - github issue #911
- Remove column item.diaspora_meta
- Provide ability to pin apps to navbar from mod apps
- Add private forums to forum widget
- Move notifications style to widgets.css
- Sort out a few more large image upload issues
- Move notifications full-screen handling to notifications widget
- Move mailhost settings from plugin to core
- Sort combined private mail conversations by latest updated conversation instead of created parent
- Filter atokens on acl search
- Allow a site to block (public) the directory separately from other resources.
- Improve removed_channel final cleanup - github issue #386
- Cleanup of upload_to_comments(
- Dedicate the first click to slideup the cover again but make sure the nav buttons remain functional
- Set os_syspath in DAV file put operation so that photos will scale correctly.
- Unit tests for Zotlabs\Access classes
- Bring back tabindex to submit comments
- attach.php minor cleanup and doc
- Allow cloud filenames to include ampersands without messing up auth tokens (zid, owt, and zat, and the constant placeholder 'f=')
- Provide short localised summary for likes that will end up in displayed notifications
- Improving Doxygen documentation.
- Update item_normal() to not include ACTIVITY_OBJ_FILE obj_type
- Sort out issues with pubstream item interactions
- Don't perform zot_refresh on dead sites unless $force is set
- Do not send message_list responses to dead sites (this delivery method bypassed the notifier)
- Support for netselect query
- Add another delivery control parameter (queue threshold)
- Add some documentation about shareable widgets
- Allow plugin class widgets
- Some more work on unit tests
- Encrypt the owa token
- Bring back the markdown post feature
- We call Theme:url() statically, make it also static.
- Table structure for pseudo or proxy channels (pchan)
Bugfixes
- Fix issue with long filenames in mod cloud
- Fix misc. issues with new 'insert photo from photo album' github issue #475
- Fix regression in channel sources delivery
- Fix loading of theme-specific widgets
- Fix unable to add wiki pages with spaces
- Fix mod display and others that require a non-zero profile_uid for updates
- Fix various PHP 7.2 issues
- Fix typo in HTTPSig
- Fix pagetitle lost importing a pdl element from conversation
- Fix js warning - getelementbyid (id doesn't exist)
- Fix some pubstream on/off weirdness
- Fix default addressbook has no name - github issue #921
- Fix double html ids in caldav widget if more than one sharee
- Fix regression in cdav calendar widget
- Fix sync packet not generated when deleting a file using the web browser interface
- Fix album cover thumb generator
- Fix like-button for images - github issue #826
- Fix typo - github issue #910
- Fix issue with group_rmv()
- Fix php warnings on photo delete
- Fix some conflicts between private tags and forum tags
- Fix some schema issues
- Fix wiki pages not updating after creating new page
- Fix a PHP warning in Permissions::FilledPerms()
- Fix unicode characters in urls tripping up url regexes - github issue #901
- Fix second half of github issue #893
- Fix common connections on suggestion page showing wildly different results than remote profile, and is consistently off by one
- Fix cloud redirects with owt tokens
- Fix issues with diaspora xchans
- Fix memory overflow trying to delete a connection with a very high noise to signal ratio
- Fix sql error in page module
- Fix unstar
Hubzilla 2.8.1 (2017-11-11) Hubzilla 2.8.1 (2017-11-11)
- Rename channel app events to calendar and add nav_set_selected() to /cal - Rename channel app events to calendar and add nav_set_selected() to /cal
- Load notifications links to /display via ajax if we are already in /display - Load notifications links to /display via ajax if we are already in /display

View File

@ -98,6 +98,8 @@ class Hq extends \Zotlabs\Web\Controller {
$sys = get_sys_channel(); $sys = get_sys_channel();
$sql_extra = item_permissions_sql($sys['channel_id']); $sql_extra = item_permissions_sql($sys['channel_id']);
$sys_item = false;
} }
if(! $update) { if(! $update) {
@ -215,6 +217,8 @@ class Hq extends \Zotlabs\Web\Controller {
} }
if(!$r) { if(!$r) {
$sys_item = true;
$r = q("SELECT item.id AS item_id FROM item $r = q("SELECT item.id AS item_id FROM item
LEFT JOIN abook ON item.author_xchan = abook.abook_xchan LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
WHERE mid = '%s' AND item.uid = %d $item_normal WHERE mid = '%s' AND item.uid = %d $item_normal
@ -243,6 +247,8 @@ class Hq extends \Zotlabs\Web\Controller {
} }
if(!$r) { if(!$r) {
$sys_item = true;
$r = q("SELECT item.parent AS item_id FROM item $r = q("SELECT item.parent AS item_id FROM item
LEFT JOIN abook ON item.author_xchan = abook.abook_xchan LEFT JOIN abook ON item.author_xchan = abook.abook_xchan
WHERE mid = '%s' AND item.uid = %d $item_normal_update $simple_update WHERE mid = '%s' AND item.uid = %d $item_normal_update $simple_update
@ -268,7 +274,7 @@ class Hq extends \Zotlabs\Web\Controller {
dbesc($parents_str) dbesc($parents_str)
); );
xchan_query($items,true,local_channel()); xchan_query($items,true,(($sys_item) ? local_channel() : 0));
$items = fetch_post_tags($items,true); $items = fetch_post_tags($items,true);
$items = conv_sort($items,'created'); $items = conv_sort($items,'created');
} }

View File

@ -156,7 +156,7 @@ class Item extends \Zotlabs\Web\Controller {
if(! x($_REQUEST,'type')) if(! x($_REQUEST,'type'))
$_REQUEST['type'] = 'net-comment'; $_REQUEST['type'] = 'net-comment';
if($obj_type == ACTIVITY_OBJ_POST) if($obj_type == ACTIVITY_OBJ_NOTE)
$obj_type = ACTIVITY_OBJ_COMMENT; $obj_type = ACTIVITY_OBJ_COMMENT;
if($parent) { if($parent) {

View File

@ -279,8 +279,8 @@ class Ping extends \Zotlabs\Web\Controller {
'photo' => $tt['photo'], 'photo' => $tt['photo'],
'when' => relative_date($tt['created']), 'when' => relative_date($tt['created']),
'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'), 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
'b64mid' => $b64mid, 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'),
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : ''), 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'),
'message' => $message 'message' => $message
); );
} }

View File

@ -2,8 +2,6 @@
namespace Zotlabs\Render; namespace Zotlabs\Render;
require_once('library/Smarty/libs/Smarty.class.php');
class SmartyInterface extends \Smarty { class SmartyInterface extends \Smarty {
public $filename; public $filename;

View File

@ -36,15 +36,17 @@
"league/html-to-markdown": "^4.4", "league/html-to-markdown": "^4.4",
"pear/text_languagedetect": "^1.0", "pear/text_languagedetect": "^1.0",
"commerceguys/intl": "~0.7", "commerceguys/intl": "~0.7",
"lukasreschke/id3parser": "^0.0.1" "lukasreschke/id3parser": "^0.0.1",
"smarty/smarty": "~3.1"
}, },
"require-dev" : { "require-dev" : {
"php" : ">=7.0", "php" : ">=7.0",
"phpunit/phpunit" : "^6.1", "phpunit/phpunit" : "~6.4.4",
"behat/behat" : "@stable", "behat/behat" : "@stable",
"behat/mink-extension": "@stable", "behat/mink-extension": "@stable",
"behat/mink-goutte-driver": "@stable", "behat/mink-goutte-driver": "@stable",
"php-mock/php-mock-phpunit": "^2.0" "php-mock/php-mock-phpunit": "^2.0",
"phpunit/dbunit": "^3.0"
}, },
"autoload" : { "autoload" : {
"psr-4" : { "psr-4" : {

618
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,9 @@
[h3]Zot API[/h3] [h3]Zot API[/h3]
Many existing social applications and tools can interface directly using the Twitter/StatusNet API, which is available using the 'twitter_api' addon.
This document describes the native API; which allows direct programmatic access to several internal data structures and libraries extending beyond the basic social interface.
The API endpoints detailed below are relative to [code]api/z/1.0[/code], meaning that if an API is listed as [code]channel/stream[/code] the full API URL is [code][baseurl]/api/z/1.0/channel/stream[/code]. The API endpoints detailed below are relative to [code]api/z/1.0[/code], meaning that if an API is listed as [code]channel/stream[/code] the full API URL is [code][baseurl]/api/z/1.0/channel/stream[/code].
[h3]channel/export/basic[/h3] [h3]channel/export/basic[/h3]

View File

@ -941,27 +941,34 @@ function bbcode($Text, $options = []) {
// Check for h1 // Check for h1
if (strpos($Text,'[h1]') !== false) { if (strpos($Text,'[h1]') !== false) {
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text); $Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'<h1>$1</h1>',$Text);
$Text = str_replace('</h1><br />', '</h1>', $Text);
} }
// Check for h2 // Check for h2
if (strpos($Text,'[h2]') !== false) { if (strpos($Text,'[h2]') !== false) {
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text); $Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'<h2>$1</h2>',$Text);
$Text = str_replace('</h2><br />', '</h2>', $Text);
} }
// Check for h3 // Check for h3
if (strpos($Text,'[h3]') !== false) { if (strpos($Text,'[h3]') !== false) {
$Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'<h3>$1</h3>',$Text); $Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'<h3>$1</h3>',$Text);
$Text = str_replace('</h3><br />', '</h3>', $Text);
} }
// Check for h4 // Check for h4
if (strpos($Text,'[h4]') !== false) { if (strpos($Text,'[h4]') !== false) {
$Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'<h4>$1</h4>',$Text); $Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'<h4>$1</h4>',$Text);
$Text = str_replace('</h4><br />', '</h4>', $Text);
} }
// Check for h5 // Check for h5
if (strpos($Text,'[h5]') !== false) { if (strpos($Text,'[h5]') !== false) {
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text); $Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'<h5>$1</h5>',$Text);
$Text = str_replace('</h5><br />', '</h5>', $Text);
} }
// Check for h6 // Check for h6
if (strpos($Text,'[h6]') !== false) { if (strpos($Text,'[h6]') !== false) {
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text); $Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text);
$Text = str_replace('</h6><br />', '</h6>', $Text);
} }
// Check for table of content without params // Check for table of content without params
while(strpos($Text,'[toc]') !== false) { while(strpos($Text,'[toc]') !== false) {
$toc_id = 'toc-' . random_string(10); $toc_id = 'toc-' . random_string(10);

View File

@ -1305,7 +1305,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) {
// allow likes of comments // allow likes of comments
if($item_parent_mid && activity_match($datarray['verb'],ACTVITY_LIKE)) { if($item_parent_mid && activity_match($datarray['verb'],ACTIVITY_LIKE)) {
$datarray['thr_parent'] = $item_parent_mid[0]['parent_mid']; $datarray['thr_parent'] = $item_parent_mid[0]['parent_mid'];
} }

View File

@ -196,12 +196,12 @@ function html2bbcode($message)
//node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]"); //node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]");
//node2bbcode($doc, 'td', array(), "[td]", "[/td]"); //node2bbcode($doc, 'td', array(), "[td]", "[/td]");
node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n"); node2bbcode($doc, 'h1', array(), "\n\n[h1]", "[/h1]\n");
node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n"); node2bbcode($doc, 'h2', array(), "\n\n[h2]", "[/h2]\n");
node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n"); node2bbcode($doc, 'h3', array(), "\n\n[h3]", "[/h3]\n");
node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n"); node2bbcode($doc, 'h4', array(), "\n\n[h4]", "[/h4]\n");
node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n"); node2bbcode($doc, 'h5', array(), "\n\n[h5]", "[/h5]\n");
node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n"); node2bbcode($doc, 'h6', array(), "\n\n[h6]", "[/h6]\n");
node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]'); node2bbcode($doc, 'a', array('href'=>'/(.+)/'), '[url=$1]', '[/url]');

View File

@ -215,7 +215,7 @@ function send_message($uid = 0, $recipient = '', $body = '', $subject = '', $rep
return $ret; return $ret;
} }
if(count($images)) { if($images) {
foreach($images as $image) { foreach($images as $image) {
if(! stristr($image,z_root() . '/photo/')) if(! stristr($image,z_root() . '/photo/'))
continue; continue;

View File

@ -1754,9 +1754,14 @@ function get_plink($item,$conversation_mode = true) {
else else
$key = 'llink'; $key = 'llink';
$zidify = true;
if(array_key_exists('author',$item) && $item['author']['xchan_network'] !== 'zot')
$zidify = false;
if(x($item,$key)) { if(x($item,$key)) {
return array( return array(
'href' => zid($item[$key]), 'href' => (($zidify) ? zid($item[$key]) : $item[$key]),
'title' => t('Link to Source'), 'title' => t('Link to Source'),
); );
} }

View File

@ -1,78 +0,0 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {counter} function plugin
* Type: function<br>
* Name: counter<br>
* Purpose: print out a counter value
*
* @author Monte Ohrt <monte at ohrt dot com>
* @link http://www.smarty.net/manual/en/language.function.counter.php {counter}
* (Smarty online manual)
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string|null
*/
function smarty_function_counter($params, $template)
{
static $counters = array();
$name = (isset($params['name'])) ? $params['name'] : 'default';
if (!isset($counters[$name])) {
$counters[$name] = array(
'start' => 1,
'skip' => 1,
'direction' => 'up',
'count' => 1
);
}
$counter =& $counters[$name];
if (isset($params['start'])) {
$counter['start'] = $counter['count'] = (int) $params['start'];
}
if (!empty($params['assign'])) {
$counter['assign'] = $params['assign'];
}
if (isset($counter['assign'])) {
$template->assign($counter['assign'], $counter['count']);
}
if (isset($params['print'])) {
$print = (bool) $params['print'];
} else {
$print = empty($counter['assign']);
}
if ($print) {
$retval = $counter['count'];
} else {
$retval = null;
}
if (isset($params['skip'])) {
$counter['skip'] = $params['skip'];
}
if (isset($params['direction'])) {
$counter['direction'] = $params['direction'];
}
if ($counter['direction'] == "down") {
$counter['count'] -= $counter['skip'];
} else {
$counter['count'] += $counter['skip'];
}
return $retval;
}

View File

@ -1,91 +0,0 @@
<?php
/**
* Smarty plugin
* This plugin is only for Smarty2 BC
*
* @package Smarty
* @subpackage PluginsFunction
*/
/**
* Smarty {math} function plugin
* Type: function<br>
* Name: math<br>
* Purpose: handle math computations in template
*
* @link http://www.smarty.net/manual/en/language.function.math.php {math}
* (Smarty online manual)
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param array $params parameters
* @param Smarty_Internal_Template $template template object
*
* @return string|null
*/
function smarty_function_math($params, $template)
{
static $_allowed_funcs = array(
'int' => true, 'abs' => true, 'ceil' => true, 'cos' => true, 'exp' => true, 'floor' => true,
'log' => true, 'log10' => true, 'max' => true, 'min' => true, 'pi' => true, 'pow' => true,
'rand' => true, 'round' => true, 'sin' => true, 'sqrt' => true, 'srand' => true, 'tan' => true
);
// be sure equation parameter is present
if (empty($params['equation'])) {
trigger_error("math: missing equation parameter", E_USER_WARNING);
return;
}
$equation = $params['equation'];
// make sure parenthesis are balanced
if (substr_count($equation, "(") != substr_count($equation, ")")) {
trigger_error("math: unbalanced parenthesis", E_USER_WARNING);
return;
}
// match all vars in equation, make sure all are passed
preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]*)!", $equation, $match);
foreach ($match[1] as $curr_var) {
if ($curr_var && !isset($params[$curr_var]) && !isset($_allowed_funcs[$curr_var])) {
trigger_error("math: function call $curr_var not allowed", E_USER_WARNING);
return;
}
}
foreach ($params as $key => $val) {
if ($key != "equation" && $key != "format" && $key != "assign") {
// make sure value is not empty
if (strlen($val) == 0) {
trigger_error("math: parameter $key is empty", E_USER_WARNING);
return;
}
if (!is_numeric($val)) {
trigger_error("math: parameter $key: is not numeric", E_USER_WARNING);
return;
}
$equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation);
}
}
$smarty_math_result = null;
eval("\$smarty_math_result = " . $equation . ";");
if (empty($params['format'])) {
if (empty($params['assign'])) {
return $smarty_math_result;
} else {
$template->assign($params['assign'], $smarty_math_result);
}
} else {
if (empty($params['assign'])) {
printf($params['format'], $smarty_math_result);
} else {
$template->assign($params['assign'], sprintf($params['format'], $smarty_math_result));
}
}
}

View File

@ -1,50 +0,0 @@
<?php
/**
* Smarty plugin
*
* @package Smarty
* @subpackage PluginsModifierCompiler
*/
/**
* Smarty unescape modifier plugin
* Type: modifier<br>
* Name: unescape<br>
* Purpose: unescape html entities
*
* @author Rodney Rehm
*
* @param array $params parameters
*
* @return string with compiled code
*/
function smarty_modifiercompiler_unescape($params)
{
if (!isset($params[1])) {
$params[1] = 'html';
}
if (!isset($params[2])) {
$params[2] = '\'' . addslashes(Smarty::$_CHARSET) . '\'';
} else {
$params[2] = "'" . $params[2] . "'";
}
switch (trim($params[1], '"\'')) {
case 'entity':
case 'htmlall':
if (Smarty::$_MBSTRING) {
return 'mb_convert_encoding(' . $params[0] . ', ' . $params[2] . ', \'HTML-ENTITIES\')';
}
return 'html_entity_decode(' . $params[0] . ', ENT_NOQUOTES, ' . $params[2] . ')';
case 'html':
return 'htmlspecialchars_decode(' . $params[0] . ', ENT_QUOTES)';
case 'url':
return 'rawurldecode(' . $params[0] . ')';
default:
return $params[0];
}
}

View File

@ -1,53 +0,0 @@
<?php
/**
* Smarty shared plugin
*
* @package Smarty
* @subpackage PluginsShared
*/
if (version_compare(PHP_VERSION, '5.2.3', '>=')) {
/**
* escape_special_chars common function
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
*
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param string $string text that should by escaped
*
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = htmlspecialchars($string, ENT_COMPAT, Smarty::$_CHARSET, false);
}
return $string;
}
} else {
/**
* escape_special_chars common function
* Function: smarty_function_escape_special_chars<br>
* Purpose: used by other smarty functions to escape
* special chars except for already escaped ones
*
* @author Monte Ohrt <monte at ohrt dot com>
*
* @param string $string text that should by escaped
*
* @return string
*/
function smarty_function_escape_special_chars($string)
{
if (!is_array($string)) {
$string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
$string = htmlspecialchars($string);
$string = str_replace(array('%%%SMARTY_START%%%', '%%%SMARTY_END%%%'), array('&', ';'), $string);
}
return $string;
}
}

View File

@ -1,98 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Assign
* Compiles the {assign} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Assign Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Assign extends Smarty_Internal_CompileBase
{
/**
* Valid scope names
*
* @var array
*/
public $valid_scopes = array('local' => true, 'parent' => true, 'root' => true, 'global' => true,
'smarty' => true, 'tpl_root' => true);
/**
* Compiles code for the {assign} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// the following must be assigned at runtime because it will be overwritten in Smarty_Internal_Compile_Append
$this->required_attributes = array('var', 'value');
$this->shorttag_order = array('var', 'value');
$this->optional_attributes = array('scope', 'bubble_up');
$_nocache = 'null';
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
// nocache ?
if ($compiler->tag_nocache || $compiler->nocache) {
$_nocache = 'true';
// create nocache var to make it know for further compiling
if (isset($compiler->template->tpl_vars[trim($_attr['var'], "'")])) {
$compiler->template->tpl_vars[trim($_attr['var'], "'")]->nocache = true;
} else {
$compiler->template->tpl_vars[trim($_attr['var'], "'")] = new Smarty_Variable(null, true);
}
}
// scope setup
$_scope = Smarty::SCOPE_LOCAL;
if (isset($_attr['scope'])) {
$_attr['scope'] = trim($_attr['scope'], "'\"");
if (!isset($this->valid_scopes[$_attr['scope']])) {
$compiler->trigger_template_error("illegal value '{$_attr['scope']}' for \"scope\" attribute", null, true);
}
if ($_attr['scope'] != 'local') {
if ($_attr['scope'] == 'parent') {
$_scope = Smarty::SCOPE_PARENT;
} elseif ($_attr['scope'] == 'root') {
$_scope = Smarty::SCOPE_ROOT;
} elseif ($_attr['scope'] == 'global') {
$_scope = Smarty::SCOPE_GLOBAL;
} elseif ($_attr['scope'] == 'smarty') {
$_scope = Smarty::SCOPE_SMARTY;
} elseif ($_attr['scope'] == 'tpl_root') {
$_scope = Smarty::SCOPE_TPL_ROOT;
}
$_scope += (isset($_attr['bubble_up']) && $_attr['bubble_up'] == 'false') ? 0 : Smarty::SCOPE_BUBBLE_UP;
}
}
// compiled output
if (isset($parameter['smarty_internal_index'])) {
$output =
"<?php \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, $_attr[var], $_nocache);\n\$_smarty_tpl->tpl_vars[$_attr[var]]->value$parameter[smarty_internal_index] = $_attr[value];";
} else {
// implement Smarty2's behaviour of variables assigned by reference
if ($compiler->template->smarty instanceof SmartyBC) {
$output =
"<?php if (isset(\$_smarty_tpl->tpl_vars[$_attr[var]])) {\$_smarty_tpl->tpl_vars[$_attr[var]] = clone \$_smarty_tpl->tpl_vars[$_attr[var]];";
$output .= "\n\$_smarty_tpl->tpl_vars[$_attr[var]]->value = $_attr[value]; \$_smarty_tpl->tpl_vars[$_attr[var]]->nocache = $_nocache;";
$output .= "\n} else \$_smarty_tpl->tpl_vars[$_attr[var]] = new Smarty_Variable($_attr[value], $_nocache);";
} else {
$output = "<?php \$_smarty_tpl->tpl_vars[$_attr[var]] = new Smarty_Variable($_attr[value], $_nocache);";
}
}
$output .= "\n\$_smarty_tpl->ext->_updateScope->updateScope(\$_smarty_tpl, $_attr[var], $_scope);";
$output .= '?>';
return $output;
}
}

View File

@ -1,292 +0,0 @@
<?php
/*
* This file is part of Smarty.
*
* (c) 2015 Uwe Tews
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Smarty Internal Plugin Compile Block Class
*
* @author Uwe Tews <uwe.tews@googlemail.com>
*/
class Smarty_Internal_Compile_Block extends Smarty_Internal_Compile_Shared_Inheritance
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $required_attributes = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('name');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $option_flags = array('hide', 'nocache');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('assign');
/**
* nesting level of block tags
*
* @var int
*/
public static $blockTagNestingLevel = 0;
/**
* Saved compiler object
*
* @var Smarty_Internal_TemplateCompilerBase
*/
public $compiler = null;
/**
* Compiles code for the {block} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return bool true
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->_cache['blockNesting'] = 0;
}
if ($compiler->_cache['blockNesting'] == 0) {
// make sure that inheritance gets initialized in template code
$this->registerInit($compiler);
$this->option_flags = array('hide', 'nocache', 'append', 'prepend');
} else {
$this->option_flags = array('hide', 'nocache');
}
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$compiler->_cache['blockNesting'] ++;
$compiler->_cache['blockName'][$compiler->_cache['blockNesting']] = $_attr['name'];
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][0] = 'block_' . preg_replace('![^\w]+!', '_', uniqid(rand(), true));
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = false;
$this->openTag($compiler, 'block', array($_attr, $compiler->nocache, $compiler->parser->current_buffer,
$compiler->template->compiled->has_nocache_code,
$compiler->template->caching));
// must whole block be nocache ?
if ($compiler->tag_nocache) {
$i = 0;
}
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// $compiler->suppressNocacheProcessing = true;
if ($_attr['nocache'] === true) {
//$compiler->trigger_template_error('nocache option not allowed', $compiler->parser->lex->taglineno);
}
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
$compiler->template->compiled->has_nocache_code = false;
$compiler->suppressNocacheProcessing = true;
}
/**
* Compile saved child block source
*
* @param \Smarty_Internal_TemplateCompilerBase compiler object
* @param string $_name optional name of child block
*
* @return string compiled code of child block
*/
static function compileChildBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null)
{
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(' tag {$smarty.block.child} used outside {block} tags ',
$compiler->parser->lex->taglineno);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
$compiler->_cache['blockParams'][$compiler->_cache['blockNesting']][1] = true;
$output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 2, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n";
return $output;
}
/**
* Compile $smarty.block.parent
*
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param string $_name optional name of child block
*
* @return string compiled code of child block
*/
static function compileParentBlock(Smarty_Internal_TemplateCompilerBase $compiler, $_name = null)
{
if (!isset($compiler->_cache['blockNesting'])) {
$compiler->trigger_template_error(' tag {$smarty.block.parent} used outside {block} tags ',
$compiler->parser->lex->taglineno);
}
$compiler->suppressNocacheProcessing = true;
$compiler->has_code = true;
$output = "<?php \n\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 4, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, null, \$_blockParentStack);\n?>\n";
return $output;
}
}
/**
* Smarty Internal Plugin Compile BlockClose Class
*
*/
class Smarty_Internal_Compile_Blockclose extends Smarty_Internal_Compile_Shared_Inheritance
{
/**
* Compiles code for the {/block} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return bool true
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
list($_attr, $_nocache, $_buffer, $_has_nocache_code, $_caching) = $this->closeTag($compiler, array('block'));
// init block parameter
$_block = $compiler->_cache['blockParams'][$compiler->_cache['blockNesting']];
unset($compiler->_cache['blockParams'][$compiler->_cache['blockNesting']]);
$_block[2] = $_block[3] = 0;
$_name = trim($_attr['name'], "'\"");
$_assign = isset($_attr['assign']) ? $_attr['assign'] : null;
unset($_attr['assign'], $_attr['name']);
foreach ($_attr as $name => $stat) {
if ((is_bool($stat) && $stat !== false) || (!is_bool($stat) && $stat != 'false')) {
$_block[$name] = is_string($stat) ? trim($stat, "'\"") : $stat;
}
}
$_funcName = $_block[0];
// get compiled block code
$_functionCode = $compiler->parser->current_buffer;
// setup buffer for template function code
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
if ($compiler->template->compiled->has_nocache_code) {
// $compiler->parent_compiler->template->tpl_function[$_name]['call_name_caching'] = $_funcNameCaching;
$_block[6] = $_funcNameCaching = $_funcName . '_nocache';
$output = "<?php\n";
$output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n";
$output .= "function {$_funcNameCaching} (\$_smarty_tpl, \$_blockParentStack) {\n";
$output .= "/*/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n";
$output .= "\$_smarty_tpl->cached->hashes['{$compiler->template->compiled->nocache_hash}'] = true;\n";
if (isset($_assign)) {
$output .= "ob_start();\n";
}
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php\n";
if (isset($_assign)) {
$output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n";
}
$output .= "/*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%*/\n";
$output .= "}\n";
$output .= "/* {/block '{$_name}'} */\n\n";
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->blockOrFunctionCode .= $f = $compiler->parser->current_buffer->to_smarty_php($compiler->parser);
$compiler->parser->current_buffer = new Smarty_Internal_ParseTree_Template();
$this->compiler = $compiler;
$_functionCode = new Smarty_Internal_ParseTree_Tag($compiler->parser,
preg_replace_callback("/((<\?php )?echo '\/\*%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/([\S\s]*?)\/\*\/%%SmartyNocache:{$compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/",
array($this, 'removeNocache'),
$_functionCode->to_smarty_php($compiler->parser)));
$this->compiler = null;
}
$output = "<?php\n";
$output .= "/* {block '{$_name}'} {$compiler->template->source->type}:{$compiler->template->source->name} */\n";
$output .= "function {$_funcName}(\$_smarty_tpl, \$_blockParentStack) {\n";
if (isset($_assign)) {
$output .= "ob_start();\n";
}
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->parser->current_buffer->append_subtree($compiler->parser, $_functionCode);
$output = "<?php\n";
if (isset($_assign)) {
$output .= "\$_smarty_tpl->tpl_vars[{$_assign}] = new Smarty_Variable(ob_get_clean());\n";
}
$output .= "}\n";
$output .= "/* {/block '{$_name}'} */\n\n";
$output .= "?>\n";
$compiler->parser->current_buffer->append_subtree($compiler->parser,
new Smarty_Internal_ParseTree_Tag($compiler->parser,
$output));
$compiler->blockOrFunctionCode .= $compiler->parser->current_buffer->to_smarty_php($compiler->parser);
// nocache plugins must be copied
if (!empty($compiler->template->compiled->required_plugins['nocache'])) {
foreach ($compiler->template->compiled->required_plugins['nocache'] as $plugin => $tmp) {
foreach ($tmp as $type => $data) {
$compiler->parent_compiler->template->compiled->required_plugins['compiled'][$plugin][$type] =
$data;
}
}
}
// restore old status
$compiler->template->compiled->has_nocache_code = $_has_nocache_code;
$compiler->tag_nocache = $compiler->nocache;
$compiler->nocache = $_nocache;
$compiler->parser->current_buffer = $_buffer;
$output = "<?php \n";
if ($compiler->_cache['blockNesting'] == 1) {
$output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " .
var_export($_block, true) . ");\n";
} else {
$output .= "\$_smarty_tpl->ext->_inheritance->processBlock(\$_smarty_tpl, 0, {$compiler->_cache['blockName'][$compiler->_cache['blockNesting']]}, " .
var_export($_block, true) . ", \$_blockParentStack);\n";
}
$output .= "?>\n";
$compiler->_cache['blockNesting'] --;
if ($compiler->_cache['blockNesting'] == 0) {
unset($compiler->_cache['blockNesting']);
}
$compiler->has_code = true;
$compiler->suppressNocacheProcessing = true;
return $output;
}
/**
* @param $match
*
* @return mixed
*/
function removeNocache($match)
{
$code =
preg_replace("/((<\?php )?echo '\/\*%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/)|(\/\*\/%%SmartyNocache:{$this->compiler->template->compiled->nocache_hash}%%\*\/';(\?>\n)?)/",
'', $match[0]);
$code = str_replace(array('\\\'', '\\\\\''), array('\'', '\\\''), $code);
return $code;
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Break
* Compiles the {break} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Break Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Break extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('levels');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('levels');
/**
* Compiles code for the {break} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true);
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', null, true);
}
if (isset($_attr['levels'])) {
if (!is_numeric($_attr['levels'])) {
$compiler->trigger_template_error('level attribute must be a numeric constant', null, true);
}
$_levels = $_attr['levels'];
} else {
$_levels = 1;
}
$level_count = $_levels;
$stack_count = count($compiler->_tag_stack) - 1;
while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) {
$level_count --;
}
$stack_count --;
}
if ($level_count != 0) {
$compiler->trigger_template_error("cannot break {$_levels} level(s)", null, true);
}
return "<?php break {$_levels};?>";
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Continue
* Compiles the {continue} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Continue Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Continue extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('levels');
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $shorttag_order = array('levels');
/**
* Compiles code for the {continue} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
static $_is_loopy = array('for' => true, 'foreach' => true, 'while' => true, 'section' => true);
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->trigger_template_error('nocache option not allowed', null, true);
}
if (isset($_attr['levels'])) {
if (!is_numeric($_attr['levels'])) {
$compiler->trigger_template_error('level attribute must be a numeric constant', null, true);
}
$_levels = $_attr['levels'];
} else {
$_levels = 1;
}
$level_count = $_levels;
$stack_count = count($compiler->_tag_stack) - 1;
while ($level_count > 0 && $stack_count >= 0) {
if (isset($_is_loopy[$compiler->_tag_stack[$stack_count][0]])) {
$level_count --;
}
$stack_count --;
}
if ($level_count != 0) {
$compiler->trigger_template_error("cannot continue {$_levels} level(s)", null, true);
}
return "<?php continue {$_levels};?>";
}
}

View File

@ -1,252 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile If
* Compiles the {if} {else} {elseif} {/if} tags
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile If Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_If extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {if} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$this->openTag($compiler, 'if', array(1, $compiler->nocache));
// must whole block be nocache ?
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
if (!array_key_exists("if condition", $parameter)) {
$compiler->trigger_template_error("missing if condition", null, true);
}
if (is_array($parameter['if condition'])) {
if ($compiler->nocache) {
$_nocache = ',true';
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = trim($parameter['if condition']['var']['var'], "'");
} else {
$var = trim($parameter['if condition']['var'], "'");
}
if (isset($compiler->template->tpl_vars[$var])) {
$compiler->template->tpl_vars[$var]->nocache = true;
} else {
$compiler->template->tpl_vars[$var] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
}
if (is_array($parameter['if condition']['var'])) {
$_output = "<?php if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]) || !is_array(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " . $parameter['if condition']['var']['var'] .
"$_nocache);\n";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output = "<?php if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"])) \$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"] = new Smarty_Variable(null{$_nocache});";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
return $_output;
} else {
return "<?php if ({$parameter['if condition']}) {?>";
}
}
}
/**
* Smarty Internal Plugin Compile Else Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Else extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {else} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
list($nesting, $compiler->tag_nocache) = $this->closeTag($compiler, array('if', 'elseif'));
$this->openTag($compiler, 'else', array($nesting, $compiler->tag_nocache));
return "<?php } else { ?>";
}
}
/**
* Smarty Internal Plugin Compile ElseIf Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Elseif extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {elseif} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
list($nesting, $compiler->tag_nocache) = $this->closeTag($compiler, array('if', 'elseif'));
if (!array_key_exists("if condition", $parameter)) {
$compiler->trigger_template_error("missing elseif condition", null, true);
}
if (is_array($parameter['if condition'])) {
$condition_by_assign = true;
if ($compiler->nocache) {
$_nocache = ',true';
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = trim($parameter['if condition']['var']['var'], "'");
} else {
$var = trim($parameter['if condition']['var'], "'");
}
if (isset($compiler->template->tpl_vars[$var])) {
$compiler->template->tpl_vars[$var]->nocache = true;
} else {
$compiler->template->tpl_vars[$var] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
}
} else {
$condition_by_assign = false;
}
if (empty($compiler->prefix_code)) {
if ($condition_by_assign) {
$this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
if (is_array($parameter['if condition']['var'])) {
$_output = "<?php } else { if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] . "]) || !is_array(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " .
$parameter['if condition']['var']['var'] . "$_nocache);\n";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output = "<?php } else { if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] . "])) \$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] . "] = new Smarty_Variable(null{$_nocache});";
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
return $_output;
} else {
$this->openTag($compiler, 'elseif', array($nesting, $compiler->tag_nocache));
return "<?php } elseif ({$parameter['if condition']}) {?>";
}
} else {
$tmp = '';
foreach ($compiler->prefix_code as $code) {
$tmp = $compiler->appendCode($tmp, $code);
}
$compiler->prefix_code = array();
$tmp = $compiler->appendCode("<?php } else {?>", $tmp);
$this->openTag($compiler, 'elseif', array($nesting + 1, $compiler->tag_nocache));
if ($condition_by_assign) {
if (is_array($parameter['if condition']['var'])) {
$_output = $compiler->appendCode($tmp, "<?php if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] .
"]) || !is_array(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " .
$parameter['if condition']['var']['var'] . "$_nocache);\n");
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output = $compiler->appendCode($tmp, "<?php if (!isset(\$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] .
"])) \$_smarty_tpl->tpl_vars[" .
$parameter['if condition']['var'] .
"] = new Smarty_Variable(null{$_nocache});");
$_output .= "if (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
return $_output;
} else {
return $compiler->appendCode($tmp, "<?php if ({$parameter['if condition']}) {?>");
}
}
}
}
/**
* Smarty Internal Plugin Compile Ifclose Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Ifclose extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {/if} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
list($nesting, $compiler->nocache) = $this->closeTag($compiler, array('if', 'else', 'elseif'));
$tmp = '';
for ($i = 0; $i < $nesting; $i ++) {
$tmp .= '}';
}
return "<?php {$tmp}?>";
}
}

View File

@ -1,89 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Block Plugin
* Compiles code for the execution of block plugin
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Block Plugin Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Block_Plugin extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles code for the execution of block plugin
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block plugin
* @param string $function PHP function name
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $function)
{
if (!isset($tag[5]) || substr($tag, - 5) != 'close') {
// opening tag of block plugin
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->tag_nocache = true;
}
unset($_attr['nocache']);
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->openTag($compiler, $tag, array($_params, $compiler->nocache));
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// compile code
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} else {
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
// closing tag of block plugin, restore nocache
list($_params, $compiler->nocache) = $this->closeTag($compiler, substr($tag, 0, - 5));
// This tag does create output
$compiler->has_output = true;
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = '';
} else {
$mod_pre = ' ob_start(); ';
$mod_post = 'echo ' .
$compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'],
'value' => 'ob_get_clean()')) . ';';
}
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo {$function}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " . $mod_post .
" } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
}
return $output . "\n";
}
}

View File

@ -1,91 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Object Block Function
* Compiles code for registered objects as block function
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Object Block Function Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Object_Block_Function extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles code for the execution of block plugin
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block object
* @param string $method name of method to call
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag, $method)
{
if (!isset($tag[5]) || substr($tag, - 5) != 'close') {
// opening tag of block plugin
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache'] === true) {
$compiler->tag_nocache = true;
}
unset($_attr['nocache']);
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->openTag($compiler, $tag . '->' . $method, array($_params, $compiler->nocache));
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
// compile code
$output =
"<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}->{$method}', {$_params}); \$_block_repeat=true; echo \$_smarty_tpl->smarty->registered_objects['{$tag}'][0]->{$method}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} else {
$base_tag = substr($tag, 0, - 5);
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
// closing tag of block plugin, restore nocache
list($_params, $compiler->nocache) = $this->closeTag($compiler, $base_tag . '->' . $method);
// This tag does create output
$compiler->has_output = true;
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = '';
} else {
$mod_pre = ' ob_start(); ';
$mod_post = 'echo ' . $compiler->compileTag('private_modifier', array(),
array('modifierlist' => $parameter['modifier_list'],
'value' => 'ob_get_clean()')) . ';';
}
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo \$_smarty_tpl->smarty->registered_objects['{$base_tag}'][0]->{$method}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " .
$mod_post . " } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
}
return $output . "\n";
}
}

View File

@ -1,119 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile Registered Block
* Compiles code for the execution of a registered block function
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile Registered Block Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Private_Registered_Block extends Smarty_Internal_CompileBase
{
/**
* Attribute definition: Overwrites base class.
*
* @var array
* @see Smarty_Internal_CompileBase
*/
public $optional_attributes = array('_any');
/**
* Compiles code for the execution of a block function
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
* @param string $tag name of block function
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter, $tag)
{
if (!isset($tag[5]) || substr($tag, - 5) != 'close') {
// opening tag of block plugin
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
if ($_attr['nocache']) {
$compiler->tag_nocache = true;
}
unset($_attr['nocache']);
if (isset($compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$tag])) {
$tag_info = $compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$tag];
} else {
$tag_info = $compiler->default_handler_plugins[Smarty::PLUGIN_BLOCK][$tag];
}
// convert attributes into parameter array string
$_paramsArray = array();
foreach ($_attr as $_key => $_value) {
if (is_int($_key)) {
$_paramsArray[] = "$_key=>$_value";
} elseif ($compiler->template->caching && in_array($_key, $tag_info[2])) {
$_value = str_replace("'", "^#^", $_value);
$_paramsArray[] = "'$_key'=>^#^.var_export($_value,true).^#^";
} else {
$_paramsArray[] = "'$_key'=>$_value";
}
}
$_params = 'array(' . implode(",", $_paramsArray) . ')';
$this->openTag($compiler, $tag, array($_params, $compiler->nocache));
// maybe nocache because of nocache variables or nocache plugin
$compiler->nocache = !$tag_info[1] | $compiler->nocache | $compiler->tag_nocache;
$function = $tag_info[0];
// compile code
if (!is_array($function)) {
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} elseif (is_object($function[0])) {
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo \$_smarty_tpl->smarty->registered_plugins['block']['{$tag}'][0][0]->{$function[1]}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
} else {
$output = "<?php \$_smarty_tpl->smarty->_cache['tag_stack'][] = array('{$tag}', {$_params}); \$_block_repeat=true; echo {$function[0]}::{$function[1]}({$_params}, null, \$_smarty_tpl, \$_block_repeat);while (\$_block_repeat) { ob_start();?>";
}
} else {
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
$base_tag = substr($tag, 0, - 5);
// closing tag of block plugin, restore nocache
list($_params, $compiler->nocache) = $this->closeTag($compiler, $base_tag);
// This tag does create output
$compiler->has_output = true;
if (isset($compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) {
$function = $compiler->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag][0];
} else {
$function = $compiler->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag][0];
}
// compile code
if (!isset($parameter['modifier_list'])) {
$mod_pre = $mod_post = '';
} else {
$mod_pre = ' ob_start(); ';
$mod_post = 'echo ' .
$compiler->compileTag('private_modifier', array(), array('modifierlist' => $parameter['modifier_list'],
'value' => 'ob_get_clean()')) . ';';
}
if (!is_array($function)) {
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo {$function}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat);" . $mod_post .
" } array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
} elseif (is_object($function[0])) {
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo \$_smarty_tpl->smarty->registered_plugins['block']['{$base_tag}'][0][0]->{$function[1]}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " .
$mod_post . "} array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
} else {
$output = "<?php \$_block_content = ob_get_clean(); \$_block_repeat=false;" . $mod_pre .
" echo {$function[0]}::{$function[1]}({$_params}, \$_block_content, \$_smarty_tpl, \$_block_repeat); " .
$mod_post . "} array_pop(\$_smarty_tpl->smarty->_cache['tag_stack']);?>";
}
}
return $output . "\n";
}
}

View File

@ -1,108 +0,0 @@
<?php
/**
* Smarty Internal Plugin Compile While
* Compiles the {while} tag
*
* @package Smarty
* @subpackage Compiler
* @author Uwe Tews
*/
/**
* Smarty Internal Plugin Compile While Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_While extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {while} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
* @param array $parameter array with compilation parameter
*
* @return string compiled code
* @throws \SmartyCompilerException
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler, $parameter)
{
$compiler->loopNesting++;
// check and get attributes
$_attr = $this->getAttributes($compiler, $args);
$this->openTag($compiler, 'while', $compiler->nocache);
if (!array_key_exists("if condition", $parameter)) {
$compiler->trigger_template_error("missing while condition", null, true);
}
// maybe nocache because of nocache variables
$compiler->nocache = $compiler->nocache | $compiler->tag_nocache;
$_output = "<?php\n";
if (is_array($parameter['if condition'])) {
if ($compiler->nocache) {
$_nocache = ',true';
// create nocache var to make it know for further compiling
if (is_array($parameter['if condition']['var'])) {
$var = trim($parameter['if condition']['var']['var'], "'");
} else {
$var = trim($parameter['if condition']['var'], "'");
}
if (isset($compiler->template->tpl_vars[$var])) {
$compiler->template->tpl_vars[$var]->nocache = true;
} else {
$compiler->template->tpl_vars[$var] = new Smarty_Variable(null, true);
}
} else {
$_nocache = '';
}
if (is_array($parameter['if condition']['var'])) {
$_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]) || !is_array(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] .
"]->value)) \$_smarty_tpl->smarty->ext->_var->createLocalArrayVariable(\$_smarty_tpl, " . $parameter['if condition']['var']['var'] .
"$_nocache);\n";
$_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var']['var'] . "]->value" .
$parameter['if condition']['var']['smarty_internal_index'] . " = " .
$parameter['if condition']['value'] . ") {?>";
} else {
$_output .= "if (!isset(\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"])) \$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] .
"] = new Smarty_Variable(null{$_nocache});";
$_output .= "while (\$_smarty_tpl->tpl_vars[" . $parameter['if condition']['var'] . "]->value = " .
$parameter['if condition']['value'] . ") {?>";
}
} else {
$_output .= "while ({$parameter['if condition']}) {?>";
}
return $_output;
}
}
/**
* Smarty Internal Plugin Compile Whileclose Class
*
* @package Smarty
* @subpackage Compiler
*/
class Smarty_Internal_Compile_Whileclose extends Smarty_Internal_CompileBase
{
/**
* Compiles code for the {/while} tag
*
* @param array $args array with attributes from parser
* @param \Smarty_Internal_TemplateCompilerBase $compiler compiler object
*
* @return string compiled code
*/
public function compile($args, Smarty_Internal_TemplateCompilerBase $compiler)
{
$compiler->loopNesting--;
// must endblock be nocache?
if ($compiler->nocache) {
$compiler->tag_nocache = true;
}
$compiler->nocache = $this->closeTag($compiler, array('while'));
return "<?php }?>\n";
}
}

View File

@ -1,157 +0,0 @@
<?php
/**
* Smarty Extension handler
*
* Load extensions dynamically
*
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
* @property Smarty_Internal_Runtime_Inheritance $_inheritance
* @property Smarty_Internal_Runtime_SubTemplate $_subTemplate
* @property Smarty_Internal_Runtime_TplFunction $_tplFunction
* @property Smarty_Internal_Runtime_Var $_var
* @property Smarty_Internal_Runtime_Config $_config
* @property Smarty_Internal_Runtime_Foreach $_foreach
* @property Smarty_Internal_Runtime_Hhvm $_hhvm
* @property Smarty_Internal_Runtime_WriteFile $_writeFile
* @property Smarty_Internal_Runtime_ValidateCompiled $_validateCompiled
* @property Smarty_Internal_Runtime_CodeFrame $_codeFrame
* @property Smarty_Internal_Runtime_FilterHandler $_filterHandler
* @property Smarty_Internal_Runtime_GetIncludePath $_getIncludePath
* @property Smarty_Internal_Runtime_UpdateScope $_updateScope
* @property Smarty_Internal_Runtime_IsCached $_isCached
* @property Smarty_Internal_Runtime_CacheModify $_cacheModify
* @property Smarty_Internal_Runtime_UpdateCache $_updateCache
* @property Smarty_Internal_Method_GetTemplateVars $getTemplateVars
* @property Smarty_Internal_Method_Append $append
* @property Smarty_Internal_Method_AppendByRef $appendByRef
* @property Smarty_Internal_Method_AssignGlobal $assignGlobal
* @property Smarty_Internal_Method_AssignByRef $assignByRef
* @property Smarty_Internal_Method_LoadFilter $loadFilter
* @property Smarty_Internal_Method_LoadPlugin $loadPlugin
* @property Smarty_Internal_Method_RegisterFilter $registerFilter
* @property Smarty_Internal_Method_RegisterObject $registerObject
* @property Smarty_Internal_Method_RegisterPlugin $registerPlugin
*/
class Smarty_Internal_Extension_Handler
{
public $objType = null;
/**
* Cache for property information from generic getter/setter
* Preloaded with names which should not use with generic getter/setter
*
* @var array
*/
private $_property_info = array('AutoloadFilters' => 0, 'DefaultModifiers' => 0, 'ConfigVars' => 0,
'DebugTemplate' => 0, 'RegisteredObject' => 0, 'StreamVariable' => 0,
'TemplateVars' => 0,);#
private $resolvedProperties = array();
/**
* Call external Method
*
* @param \Smarty_Internal_Data $data
* @param string $name external method names
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function _callExternalMethod(Smarty_Internal_Data $data, $name, $args)
{
/* @var Smarty $data ->smarty */
$smarty = isset($data->smarty) ? $data->smarty : $data;
if (!isset($smarty->ext->$name)) {
$class = 'Smarty_Internal_Method_' . ucfirst($name);
if (preg_match('/^(set|get)([A-Z].*)$/', $name, $match)) {
if (!isset($this->_property_info[$prop = $match[2]])) {
// convert camel case to underscored name
$this->resolvedProperties[$prop] = $pn = strtolower(join('_',
preg_split('/([A-Z][^A-Z]*)/', $prop, - 1,
PREG_SPLIT_NO_EMPTY |
PREG_SPLIT_DELIM_CAPTURE)));
$this->_property_info[$prop] = property_exists($data, $pn) ? 1 :
($data->_objType == 2 && property_exists($smarty, $pn) ? 2 : 0);
}
if ($this->_property_info[$prop]) {
$pn = $this->resolvedProperties[$prop];
if ($match[1] == 'get') {
return $this->_property_info[$prop] == 1 ? $data->$pn : $data->smarty->$pn;
} else {
return $this->_property_info[$prop] == 1 ? $data->$pn = $args[0] :
$data->smarty->$pn = $args[0];
}
} elseif (!class_exists($class)) {
throw new SmartyException("property '$pn' does not exist.");
}
}
if (class_exists($class)) {
$callback = array($smarty->ext->$name = new $class(), $name);
}
} else {
$callback = array($smarty->ext->$name, $name);
}
array_unshift($args, $data);
if (isset($callback) && $callback[0]->objMap | $data->_objType) {
return call_user_func_array($callback, $args);
}
return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args);
}
/**
* set extension property
*
* @param string $property_name property name
* @param mixed $value value
*
* @throws SmartyException
*/
public function __set($property_name, $value)
{
$this->$property_name = $value;
}
/**
* get extension object
*
* @param string $property_name property name
*
* @return mixed|Smarty_Template_Cached
* @throws SmartyException
*/
public function __get($property_name)
{
// object properties of runtime template extensions will start with '_'
if ($property_name[0] == '_') {
$class = 'Smarty_Internal_Runtime_' . ucfirst(substr($property_name, 1));
} else {
$class = 'Smarty_Internal_Method_' . ucfirst($property_name);
}
if (class_exists($class)) {
return $this->$property_name = new $class();
}
return $this;
}
/**
* Call error handler for undefined method
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function __call($name, $args)
{
return call_user_func_array(array(new Smarty_Internal_Undefined(), $name), $args);
}
}

View File

@ -1,47 +0,0 @@
<?php
/**
* Foreach Runtime Methods count
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Foreach
{
/**
* [util function] counts an array, arrayAccess/traversable or PDOStatement object
*
* @param mixed $value
*
* @return int the count for arrays and objects that implement countable, 1 for other objects that don't, and 0
* for empty elements
*/
public function count($value)
{
if (is_array($value) === true || $value instanceof Countable) {
return count($value);
} elseif ($value instanceof IteratorAggregate) {
// Note: getIterator() returns a Traversable, not an Iterator
// thus rewind() and valid() methods may not be present
return iterator_count($value->getIterator());
} elseif ($value instanceof Iterator) {
if ($value instanceof Generator) {
return 1;
}
return iterator_count($value);
} elseif ($value instanceof PDOStatement) {
return $value->rowCount();
} elseif ($value instanceof Traversable) {
return iterator_count($value);
} elseif ($value instanceof ArrayAccess) {
if ($value->offsetExists(0)) {
return 1;
}
} elseif (is_object($value)) {
return count($value);
}
return 0;
}
}

View File

@ -1,30 +0,0 @@
<?php
/**
* Runtime Extension Hhvm
*
* include patch for modified compiled or cached templates
* HHVM does not check if file was modified when including same file multiple times
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Runtime_Hhvm
{
/**
* @param \Smarty_Internal_Template $_template
* @param string $file file name
*
* @return mixed
*/
static function includeHhvm(Smarty_Internal_Template $_template, $file)
{
$_smarty_tpl = $_template;
$tmp_file = $file . preg_replace('![^\w]+!', '_', uniqid(rand(), true)) . '.php';
file_put_contents($tmp_file, file_get_contents($file));
$result = @include $tmp_file;
@unlink($tmp_file);
return $result;
}
}

View File

@ -1,233 +0,0 @@
<?php
/**
* Inheritance Runtime Methods processBlock, endChild, init
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Inheritance
{
/**
* State machine
* - 0 idle next extends will create a new inheritance tree
* - 1 processing child template
* - 2 wait for next inheritance template
* - 3 assume parent template, if child will loaded goto state 1
* a call to a sub template resets the state to 0
*
* @var int
*/
public $state = 0;
/**
* Array of block parameter of known {block} tags
*
* @var array
*/
public $blockParameter = array();
/**
* inheritance template nesting level
*
* @var int
*/
public $inheritanceLevel = 0;
/**
* inheritance template index
*
* @var int
*/
public $tplIndex = - 1;
/**
* Array of compiled template file path
* - key template index
* only used when caching is enabled
*
* @var []string
*/
public $compiledFilePath = array();
/**
* Current {block} nesting level
*
* @var int
*/
public $blockNesting = 0;
/**
* Initialize inheritance
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param bool $initChild if true init for child template
* @param array $blockNames outer level block name
*
*/
public function init(Smarty_Internal_Template $tpl, $initChild, $blockNames = array())
{
// if template was from an inner block or template is a parent template create new inheritance root
if ($initChild && ($this->blockNesting || $this->state == 3)) {
$tpl->ext->_inheritance = new Smarty_Internal_Runtime_Inheritance();
$tpl->ext->_inheritance->init($tpl, $initChild, $blockNames);
return;
}
// start of child sub template(s)
if ($initChild) {
$this->state = 1;
if (!$this->inheritanceLevel) {
//grab any output of child templates
ob_start();
}
$this->inheritanceLevel ++;
}
// in parent state {include} will not increment template index
if ($this->state != 3) {
$this->tplIndex ++;
}
// if state was waiting for parent change state to parent
if ($this->state == 2) {
$this->state = 3;
}
}
/**
* End of child template(s)
* - if outer level is reached flush output buffer and switch to wait for parent template state
*
* @param \Smarty_Internal_Template $tpl template object of caller
*/
public function endChild(Smarty_Internal_Template $tpl)
{
$this->inheritanceLevel --;
if (!$this->inheritanceLevel) {
ob_end_clean();
$this->state = 2;
}
}
/**
* Process inheritance {block} tag
*
* $type 0 = {block}:
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise call current block
* - ignored for outer level blocks in child templates
*
* $type 1 = {block}:
* - nested {block}
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise call current block
*
* $type 2 = {$smarty.block.child}:
* - search in inheritance template hierarchy for child blocks
* if found call it, otherwise ignore
*
* $type 3 = {block append} {block prepend}:
* - call parent block
*
* $type 4 = {$smarty.block.parent}:
* - call parent block
*
* @param \Smarty_Internal_Template $tpl template object of caller
* @param int $type call type see above
* @param string $name block name
* @param array $block block parameter
* @param array $callStack call stack with block parameters
*
* @throws \SmartyException
*/
public function processBlock(Smarty_Internal_Template $tpl, $type = 0, $name, $block, $callStack = array())
{
if (!isset($this->blockParameter[ $name ])) {
$this->blockParameter[ $name ] = array();
}
if ($this->state == 1) {
$block[ 2 ] = count($this->blockParameter[ $name ]);
$block[ 3 ] = $this->tplIndex;
$this->blockParameter[ $name ][] = $block;
return;
}
if ($type == 3) {
if (!empty($callStack)) {
$block = array_shift($callStack);
} else {
return;
}
} elseif ($type == 4) {
if (!empty($callStack)) {
array_shift($callStack);
if (empty($callStack)) {
throw new SmartyException("inheritance: tag {\$smarty.block.parent} used in parent template block '{$name}'");
}
$block = array_shift($callStack);
} else {
return;
}
} else {
$index = 0;
$blockParameter = &$this->blockParameter[ $name ];
if ($type == 0) {
$index = $block[ 2 ] = count($blockParameter);
$block[ 3 ] = $this->tplIndex;
$callStack = array(&$block);
} elseif ($type == 1) {
$block[ 3 ] = $callStack[ 0 ][ 3 ];
for ($i = 0; $i < count($blockParameter); $i ++) {
if ($blockParameter[ $i ][ 3 ] <= $block[ 3 ]) {
$index = $blockParameter[ $i ][ 2 ];
}
}
$block[ 2 ] = $index;
$callStack = array(&$block);
} elseif ($type == 2) {
$index = $callStack[ 0 ][ 2 ];
if ($index == 0) {
return;
}
$callStack = $block = array(1 => false);
}
$index --;
// find lowest level child block
while ($index >= 0 && ($type || !$block[ 1 ])) {
$block = &$blockParameter[ $index ];
array_unshift($callStack, $block);
if ($block[ 1 ]) {
break;
}
$index --;
}
if (isset($block[ 'hide' ]) && $index <= 0) {
return;
}
}
$this->blockNesting ++;
// {block append} ?
if (isset($block[ 'append' ])) {
$appendStack = $callStack;
if ($type == 0) {
array_shift($appendStack);
}
$this->processBlock($tpl, 3, $name, null, $appendStack);
}
// call block of current stack level
if (isset($block[6])) {
$block[6]($tpl, $callStack);
} else {
$block[0]($tpl, $callStack);
}
// {block prepend} ?
if (isset($block[ 'prepend' ])) {
$prependStack = $callStack;
if ($type == 0) {
array_shift($prependStack);
}
$this->processBlock($tpl, 3, $name, null, $prependStack);
}
$this->blockNesting --;
}
}

View File

@ -1,203 +0,0 @@
<?php
/**
* Sub Template Runtime Methods render, setupSubTemplate
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_SubTemplate
{
/**
* Subtemplate template object cache
*
* @var Smarty_Internal_Template[]
*/
public $tplObjects = array();
/**
* Subtemplate call count
*
* @var int[]
*/
public $subTplInfo = array();
/**
* Runtime function to render subtemplate
*
* @param \Smarty_Internal_Template $parent
* @param string $template template name
* @param mixed $cache_id cache id
* @param mixed $compile_id compile id
* @param integer $caching cache mode
* @param integer $cache_lifetime life time of cache data
* @param array $data passed parameter template variables
* @param int $scope scope in which {include} should execute
* @param bool $forceTplCache cache template object
* @param string $uid file dependency uid
* @param string $content_func function name
*
*/
public function render(Smarty_Internal_Template $parent, $template, $cache_id, $compile_id, $caching,
$cache_lifetime, $data, $scope, $forceTplCache, $uid = null, $content_func = null)
{
// if there are cached template objects calculate $templateID
$_templateId =
!empty($this->tplObjects) ? $parent->smarty->_getTemplateId($template, $cache_id, $compile_id, $caching) :
null;
// already in template cache?
/* @var Smarty_Internal_Template $tpl */
if (isset($_templateId) && isset($this->tplObjects[$_templateId])) {
// clone cached template object because of possible recursive call
$tpl = clone $this->tplObjects[$_templateId];
$tpl->parent = $parent;
// if $caching mode changed the compiled resource is invalid
if ((bool) $tpl->caching !== (bool) $caching) {
unset($tpl->compiled);
}
// get variables from calling scope
$tpl->tpl_vars = $parent->tpl_vars;
$tpl->config_vars = $parent->config_vars;
// get template functions
$tpl->tpl_function = $parent->tpl_function;
// copy inheritance object?
if (isset($parent->ext->_inheritance)) {
$tpl->ext->_inheritance = $parent->ext->_inheritance;
} else {
unset($tpl->ext->_inheritance);
}
} else {
$tpl = clone $parent;
$tpl->parent = $parent;
if (!isset($tpl->templateId) || $tpl->templateId !== $_templateId) {
$tpl->templateId = $_templateId;
$tpl->template_resource = $template;
$tpl->cache_id = $cache_id;
$tpl->compile_id = $compile_id;
if (isset($uid)) {
// for inline templates we can get all resource information from file dependency
if (isset($tpl->compiled->file_dependency[$uid])) {
list($filepath, $timestamp, $resource) = $tpl->compiled->file_dependency[$uid];
$tpl->source =
new Smarty_Template_Source(isset($tpl->smarty->_cache['resource_handlers'][$resource]) ?
$tpl->smarty->_cache['resource_handlers'][$resource] :
Smarty_Resource::load($tpl->smarty, $resource), $tpl->smarty,
$filepath, $resource, $filepath);
$tpl->source->filepath = $filepath;
$tpl->source->timestamp = $timestamp;
$tpl->source->exists = true;
$tpl->source->uid = $uid;
} else {
$tpl->source = null;
}
} else {
$tpl->source = null;
}
if (!isset($tpl->source)) {
$tpl->source = Smarty_Template_Source::load($tpl);
unset($tpl->compiled);
}
unset($tpl->cached);
}
}
$tpl->caching = $caching;
$tpl->cache_lifetime = $cache_lifetime;
if ($caching == 9999) {
$tpl->cached = $parent->cached;
}
// set template scope
$tpl->scope = $scope;
$scopePtr = false;
if ($scope & ~Smarty::SCOPE_BUBBLE_UP) {
if ($scope == Smarty::SCOPE_GLOBAL) {
$tpl->tpl_vars = Smarty::$global_tpl_vars;
$tpl->config_vars = $tpl->smarty->config_vars;
$scopePtr = true;
} else {
if ($scope == Smarty::SCOPE_PARENT) {
$scopePtr = $parent;
} elseif ($scope == Smarty::SCOPE_SMARTY) {
$scopePtr = $tpl->smarty;
} else {
$scopePtr = $tpl;
while (isset($scopePtr->parent)) {
if ($scopePtr->parent->_objType != 2 && $scope & Smarty::SCOPE_TPL_ROOT) {
break;
}
$scopePtr = $scopePtr->parent;
}
}
$tpl->tpl_vars = $scopePtr->tpl_vars;
$tpl->config_vars = $scopePtr->config_vars;
}
}
if (!isset($this->tplObjects[$tpl->_getTemplateId()]) && !$tpl->source->handler->recompiled) {
// if template is called multiple times set flag to to cache template objects
$forceTplCache = $forceTplCache ||
(isset($this->subTplInfo[$tpl->template_resource]) && $this->subTplInfo[$tpl->template_resource] > 1);
// check if template object should be cached
if ($tpl->parent->_objType == 2 && isset($this->tplObjects[$tpl->parent->templateId]) ||
($forceTplCache && $tpl->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_AUTOMATIC) ||
($tpl->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON)
) {
$this->tplObjects[$tpl->_getTemplateId()] = $tpl;
}
}
if (!empty($data)) {
// set up variable values
foreach ($data as $_key => $_val) {
$tpl->tpl_vars[$_key] = new Smarty_Variable($_val);
}
}
if (isset($uid)) {
if ($parent->smarty->debugging) {
$parent->smarty->_debug->start_template($tpl);
$parent->smarty->_debug->start_render($tpl);
}
$tpl->compiled->getRenderedTemplateCode($tpl, $content_func);
if ($parent->smarty->debugging) {
$parent->smarty->_debug->end_template($tpl);
$parent->smarty->_debug->end_render($tpl);
}
if ($tpl->caching == 9999 && $tpl->compiled->has_nocache_code) {
$parent->cached->hashes[$tpl->compiled->nocache_hash] = true;
}
} else {
if (isset($tpl->compiled)) {
$tpl->compiled->render($tpl);
} else {
$tpl->render();
}
}
if ($scopePtr) {
if ($scope == Smarty::SCOPE_GLOBAL) {
Smarty::$global_tpl_vars = $tpl->tpl_vars;
$tpl->smarty->config_vars = $tpl->config_vars;
} else {
$scopePtr->tpl_vars = $tpl->tpl_vars;
$scopePtr->config_vars = $tpl->config_vars;
}
}
}
/**
* Get called subtemplates from compiled template and save call count
*
* @param \Smarty_Internal_Template $tpl
*/
public function registerSubTemplates(Smarty_Internal_Template $tpl)
{
foreach ($tpl->compiled->includes as $name => $count) {
if (isset($this->subTplInfo[$name])) {
$this->subTplInfo[$name] += $count;
} else {
$this->subTplInfo[$name] = $count;
}
}
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Tplfunc Runtime Methods callTemplateFunction
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_TplFunction
{
/**
* Call template function
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $name template function name
* @param array $params parameter array
* @param bool $nocache true if called nocache
*
* @throws \SmartyException
*/
public function callTemplateFunction(Smarty_Internal_Template $tpl, $name, $params, $nocache)
{
if (isset($tpl->tpl_function[$name])) {
if (!$tpl->caching || ($tpl->caching && $nocache)) {
$function = $tpl->tpl_function[$name]['call_name'];
} else {
if (isset($tpl->tpl_function[$name]['call_name_caching'])) {
$function = $tpl->tpl_function[$name]['call_name_caching'];
} else {
$function = $tpl->tpl_function[$name]['call_name'];
}
}
if (function_exists($function)) {
$function ($tpl, $params);
return;
}
// try to load template function dynamically
if ($this->addTplFuncToCache($tpl, $name, $function)) {
$function ($tpl, $params);
return;
}
}
throw new SmartyException("Unable to find template function '{$name}'");
}
/**
*
* Add template function to cache file for nocache calls
*
* @param Smarty_Internal_Template $tpl
* @param string $_name template function name
* @param string $_function PHP function name
*
* @return bool
*/
public function addTplFuncToCache(Smarty_Internal_Template $tpl, $_name, $_function)
{
$funcParam = $tpl->tpl_function[$_name];
if (is_file($funcParam['compiled_filepath'])) {
// read compiled file
$code = file_get_contents($funcParam['compiled_filepath']);
// grab template function
if (preg_match("/\/\* {$_function} \*\/([\S\s]*?)\/\*\/ {$_function} \*\//", $code, $match)) {
// grab source info from file dependency
preg_match("/\s*'{$funcParam['uid']}'([\S\s]*?)\),/", $code, $match1);
unset($code);
// make PHP function known
eval($match[0]);
if (function_exists($_function)) {
// search cache file template
$tplPtr = $tpl;
while (!isset($tplPtr->cached) && isset($tplPtr->parent)) {
$tplPtr = $tplPtr->parent;
}
// add template function code to cache file
if (isset($tplPtr->cached)) {
$cache = $tplPtr->cached;
$content = $cache->read($tplPtr);
if ($content) {
// check if we must update file dependency
if (!preg_match("/'{$funcParam['uid']}'(.*?)'nocache_hash'/", $content, $match2)) {
$content = preg_replace("/('file_dependency'(.*?)\()/", "\\1{$match1[0]}", $content);
}
$tplPtr->smarty->ext->_updateCache->write($cache, $tplPtr, preg_replace('/\s*\?>\s*$/', "\n", $content) . "\n" .
preg_replace(array('/^\s*<\?php\s+/', '/\s*\?>\s*$/'), "\n",
$match[0]));
}
}
return true;
}
}
}
return false;
}
}

View File

@ -1,55 +0,0 @@
<?php
/**
* Runtime Methods updateScope
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_UpdateScope
{
/**
* Update new assigned template variable in other effected scopes
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $varName variable name
* @param int $scope scope to which bubble up variable value
*/
public function updateScope(Smarty_Internal_Template $tpl, $varName, $scope = Smarty::SCOPE_LOCAL)
{
if (!$scope && !$tpl->scope) {
return;
}
foreach (array($scope, $tpl->scope) as $s) {
$s = ($bubble_up = $s >= Smarty::SCOPE_BUBBLE_UP) ? $s - Smarty::SCOPE_BUBBLE_UP : $s;
if ($bubble_up && $s) {
$ptr = $tpl->parent;
if (isset($ptr)) {
$ptr->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
$ptr = $ptr->parent;
}
if ($s == Smarty::SCOPE_PARENT) {
continue;
}
while (isset($ptr) && $ptr->_objType == 2) {
$ptr->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
$ptr = $ptr->parent;
}
if ($s == Smarty::SCOPE_TPL_ROOT) {
continue;
} elseif ($s == Smarty::SCOPE_SMARTY) {
$tpl->smarty->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
} elseif ($s == Smarty::SCOPE_GLOBAL) {
Smarty::$global_tpl_vars[$varName] = $tpl->tpl_vars[$varName];
} elseif ($s == Smarty::SCOPE_ROOT) {
while (isset($ptr->parent)) {
$ptr = $ptr->parent;
}
$ptr->tpl_vars[$varName] = $tpl->tpl_vars[$varName];
}
}
}
}
}

View File

@ -1,86 +0,0 @@
<?php
/**
* Runtime Methods decodeProperties
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_ValidateCompiled
{
/**
* This function is executed automatically when a compiled or cached template file is included
* - Decode saved properties from compiled template and cache files
* - Check if compiled or cache file is valid
*
* @param array $properties special template properties
* @param bool $cache flag if called from cache file
*
* @return bool flag if compiled or cache file is valid
*/
public function decodeProperties(Smarty_Internal_Template $tpl, $properties, $cache = false)
{
$is_valid = true;
if (Smarty::SMARTY_VERSION != $properties['version']) {
// new version must rebuild
$is_valid = false;
} elseif ($is_valid && !empty($properties['file_dependency']) &&
((!$cache && $tpl->smarty->compile_check) || $tpl->smarty->compile_check == 1)
) {
// check file dependencies at compiled code
foreach ($properties['file_dependency'] as $_file_to_check) {
if ($_file_to_check[2] == 'file' || $_file_to_check[2] == 'extends' || $_file_to_check[2] == 'php') {
if ($tpl->source->filepath == $_file_to_check[0]) {
// do not recheck current template
continue;
//$mtime = $tpl->source->getTimeStamp();
} else {
// file and php types can be checked without loading the respective resource handlers
$mtime = is_file($_file_to_check[0]) ? filemtime($_file_to_check[0]) : false;
}
} elseif ($_file_to_check[2] == 'string') {
continue;
} else {
$handler = Smarty_Resource::load($tpl->smarty, $_file_to_check[2]);
if ($handler->checkTimestamps()) {
$source = Smarty_Template_Source::load($tpl, $tpl->smarty, $_file_to_check[ 0 ]);
$mtime = $source->getTimeStamp();
} else {
continue;
}
}
if (!$mtime || $mtime > $_file_to_check[1]) {
$is_valid = false;
break;
}
}
}
if ($cache) {
// CACHING_LIFETIME_SAVED cache expiry has to be validated here since otherwise we'd define the unifunc
if ($tpl->caching === Smarty::CACHING_LIFETIME_SAVED && $properties['cache_lifetime'] >= 0 &&
(time() > ($tpl->cached->timestamp + $properties['cache_lifetime']))
) {
$is_valid = false;
}
$tpl->cached->cache_lifetime = $properties['cache_lifetime'];
$tpl->cached->valid = $is_valid;
$resource = $tpl->cached;
} else {
$tpl->mustCompile = !$is_valid;
$resource = $tpl->compiled;
$resource->includes = isset($properties['includes']) ? $properties['includes'] : array();
}
if ($is_valid) {
$resource->unifunc = $properties['unifunc'];
$resource->has_nocache_code = $properties['has_nocache_code'];
// $tpl->compiled->nocache_hash = $properties['nocache_hash'];
$resource->file_dependency = $properties['file_dependency'];
if (isset($properties['tpl_function'])) {
$tpl->tpl_function = $properties['tpl_function'];
}
}
return $is_valid && !function_exists($properties['unifunc']);
}
}

View File

@ -1,33 +0,0 @@
<?php
/**
* Runtime Methods createLocalArrayVariable
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*
**/
class Smarty_Internal_Runtime_Var
{
/**
* Template code runtime function to create a local Smarty variable for array assignments
*
* @param \Smarty_Internal_Template $tpl template object
* @param string $varName template variable name
* @param bool $nocache cache mode of variable
*/
public function createLocalArrayVariable(Smarty_Internal_Template $tpl, $varName, $nocache = false)
{
if (!isset($tpl->tpl_vars[$varName])) {
$tpl->tpl_vars[$varName] = new Smarty_Variable(array(), $nocache);
} else {
$tpl->tpl_vars[$varName] = clone $tpl->tpl_vars[$varName];
if (!(is_array($tpl->tpl_vars[$varName]->value) ||
$tpl->tpl_vars[$varName]->value instanceof ArrayAccess)
) {
settype($tpl->tpl_vars[$varName]->value, 'array');
}
}
}
}

View File

@ -1,376 +0,0 @@
<?php
/**
* Smarty Internal Plugin Template
* This file contains the Smarty template engine
*
* @package Smarty
* @subpackage Template
* @author Uwe Tews
*/
/**
* Main class with template data structures and methods
*
* @package Smarty
* @subpackage Template
*
* @property Smarty_Template_Source|Smarty_Template_Config $source
* @property Smarty_Template_Compiled $compiled
* @property Smarty_Template_Cached $cached
* @method bool mustCompile()
*/
class Smarty_Internal_Template extends Smarty_Internal_TemplateBase
{
/**
* This object type (Smarty = 1, template = 2, data = 4)
*
* @var int
*/
public $_objType = 2;
/**
* Global smarty instance
*
* @var Smarty
*/
public $smarty = null;
/**
* Source instance
*
* @var Smarty_Template_Source|Smarty_Template_Config
*/
public $source = null;
/**
* Template resource
*
* @var string
*/
public $template_resource = null;
/**
* flag if compiled template is invalid and must be (re)compiled
*
* @var bool
*/
public $mustCompile = null;
/**
* Template Id
*
* @var null|string
*/
public $templateId = null;
/**
* Known template functions
*
* @var array
*/
public $tpl_function = array();
/**
* Scope in which template is rendered
*
* @var int
*/
public $scope = 0;
/**
* Create template data object
* Some of the global Smarty settings copied to template scope
* It load the required template resources and caching plugins
*
* @param string $template_resource template resource string
* @param Smarty $smarty Smarty instance
* @param \Smarty_Internal_Template|\Smarty|\Smarty_Internal_Data $_parent back pointer to parent object
* with variables or null
* @param mixed $_cache_id cache id or null
* @param mixed $_compile_id compile id or null
* @param bool $_caching use caching?
* @param int $_cache_lifetime cache life-time in seconds
*
* @throws \SmartyException
*/
public function __construct($template_resource, Smarty $smarty, Smarty_Internal_Data $_parent = null,
$_cache_id = null, $_compile_id = null, $_caching = null, $_cache_lifetime = null)
{
$this->smarty = &$smarty;
// Smarty parameter
$this->cache_id = $_cache_id === null ? $this->smarty->cache_id : $_cache_id;
$this->compile_id = $_compile_id === null ? $this->smarty->compile_id : $_compile_id;
$this->caching = $_caching === null ? $this->smarty->caching : $_caching;
if ($this->caching === true) {
$this->caching = Smarty::CACHING_LIFETIME_CURRENT;
}
$this->cache_lifetime = $_cache_lifetime === null ? $this->smarty->cache_lifetime : $_cache_lifetime;
$this->parent = $_parent;
// Template resource
$this->template_resource = $template_resource;
$this->source = Smarty_Template_Source::load($this);
parent::__construct();
}
/**
* render template
*
* @param bool $merge_tpl_vars if true parent template variables merged in to local scope
* @param bool $no_output_filter if true do not run output filter
* @param bool $display true: display, false: fetch null: subtemplate
*
* @throws Exception
* @throws SmartyException
* @return string rendered template output
*/
public function render($no_output_filter = true, $display = null)
{
$parentIsTpl = isset($this->parent) && $this->parent->_objType == 2;
if ($this->smarty->debugging) {
$this->smarty->_debug->start_template($this, $display);
}
// checks if template exists
if (!$this->source->exists) {
if ($parentIsTpl) {
$parent_resource = " in '{$this->parent->template_resource}'";
} else {
$parent_resource = '';
}
throw new SmartyException("Unable to load template {$this->source->type} '{$this->source->name}'{$parent_resource}");
}
// disable caching for evaluated code
if ($this->source->handler->recompiled) {
$this->caching = false;
}
// read from cache or render
$isCacheTpl =
$this->caching == Smarty::CACHING_LIFETIME_CURRENT || $this->caching == Smarty::CACHING_LIFETIME_SAVED;
if ($isCacheTpl) {
if (!isset($this->cached)) {
$this->loadCached();
}
$this->cached->render($this, $no_output_filter);
} elseif ($this->source->handler->uncompiled) {
$this->source->render($this);
} else {
if (!isset($this->compiled)) {
$this->loadCompiled();
}
$this->compiled->render($this);
}
// display or fetch
if ($display) {
if ($this->caching && $this->smarty->cache_modified_check) {
$this->smarty->ext->_cachemodify->cacheModifiedCheck($this->cached, $this,
isset($content) ? $content : ob_get_clean());
} else {
if ((!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) &&
!$no_output_filter && (isset($this->smarty->autoload_filters['output']) ||
isset($this->smarty->registered_filters['output']))
) {
echo $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this);
} else {
ob_end_flush();
flush();
}
}
if ($this->smarty->debugging) {
$this->smarty->_debug->end_template($this);
// debug output
$this->smarty->_debug->display_debug($this, true);
}
return '';
} else {
if ($this->smarty->debugging) {
$this->smarty->_debug->end_template($this);
if ($this->smarty->debugging === 2 && $display === false) {
$this->smarty->_debug->display_debug($this, true);
}
}
if ($parentIsTpl) {
if (!empty($this->tpl_function)) {
$this->parent->tpl_function = array_merge($this->parent->tpl_function, $this->tpl_function);
}
foreach ($this->compiled->required_plugins as $code => $tmp1) {
foreach ($tmp1 as $name => $tmp) {
foreach ($tmp as $type => $data) {
$this->parent->compiled->required_plugins[$code][$name][$type] = $data;
}
}
}
}
if (!$no_output_filter &&
(!$this->caching || $this->cached->has_nocache_code || $this->source->handler->recompiled) &&
(isset($this->smarty->autoload_filters['output']) || isset($this->smarty->registered_filters['output']))
) {
return $this->smarty->ext->_filterHandler->runFilter('output', ob_get_clean(), $this);
}
// return cache content
return null;
}
}
/**
* Compiles the template
* If the template is not evaluated the compiled template is saved on disk
*/
public function compileTemplateSource()
{
return $this->compiled->compileTemplateSource($this);
}
/**
* Writes the content to cache resource
*
* @param string $content
*
* @return bool
*/
public function writeCachedContent($content)
{
return $this->smarty->ext->_updateCache->writeCachedContent($this->cached, $this, $content);
}
/**
* Get unique template id
*
* @return string
*/
public function _getTemplateId()
{
return isset($this->templateId) ? $this->templateId : $this->templateId =
$this->smarty->_getTemplateId($this->template_resource, $this->cache_id, $this->compile_id);
}
/**
* runtime error not matching capture tags
*/
public function capture_error()
{
throw new SmartyException("Not matching {capture} open/close in \"{$this->template_resource}\"");
}
/**
* Load compiled object
*
*/
public function loadCompiled()
{
if (!isset($this->compiled)) {
$this->compiled = Smarty_Template_Compiled::load($this);
}
}
/**
* Load cached object
*
*/
public function loadCached()
{
if (!isset($this->cached)) {
$this->cached = Smarty_Template_Cached::load($this);
}
}
/**
* Load compiler object
*
* @throws \SmartyException
*/
public function loadCompiler()
{
if (!class_exists($this->source->handler->compiler_class)) {
$this->smarty->loadPlugin($this->source->handler->compiler_class);
}
$this->compiler = new $this->source->handler->compiler_class($this->source->handler->template_lexer_class,
$this->source->handler->template_parser_class,
$this->smarty);
}
/**
* Handle unknown class methods
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function __call($name, $args)
{
// method of Smarty object?
if (method_exists($this->smarty, $name)) {
return call_user_func_array(array($this->smarty, $name), $args);
}
// parent
return parent::__call($name, $args);
}
/**
* set Smarty property in template context
*
* @param string $property_name property name
* @param mixed $value value
*
* @throws SmartyException
*/
public function __set($property_name, $value)
{
switch ($property_name) {
case 'compiled':
case 'cached':
case 'compiler':
$this->$property_name = $value;
return;
default:
// Smarty property ?
if (property_exists($this->smarty, $property_name)) {
$this->smarty->$property_name = $value;
return;
}
}
throw new SmartyException("invalid template property '$property_name'.");
}
/**
* get Smarty property in template context
*
* @param string $property_name property name
*
* @return mixed|Smarty_Template_Cached
* @throws SmartyException
*/
public function __get($property_name)
{
switch ($property_name) {
case 'compiled':
$this->loadCompiled();
return $this->compiled;
case 'cached':
$this->loadCached();
return $this->cached;
case 'compiler':
$this->loadCompiler();
return $this->compiler;
default:
// Smarty property ?
if (property_exists($this->smarty, $property_name)) {
return $this->smarty->$property_name;
}
}
throw new SmartyException("template property '$property_name' does not exist.");
}
/**
* Template data object destructor
*/
public function __destruct()
{
if ($this->smarty->cache_locking && isset($this->cached) && $this->cached->is_locked) {
$this->cached->handler->releaseLock($this->smarty, $this->cached);
}
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* Smarty Method AppendByRef
*
* Smarty::appendByRef() method
*
* @package Smarty
* @subpackage PluginsInternal
* @author Uwe Tews
*/
class Smarty_Internal_Undefined
{
/**
* This function is executed automatically when a compiled or cached template file is included
* - Decode saved properties from compiled template and cache files
* - Check if compiled or cache file is valid
*
* @param array $properties special template properties
* @param bool $cache flag if called from cache file
*
* @return bool flag if compiled or cache file is valid
*/
public function decodeProperties($tpl, $properties, $cache = false)
{
if ($cache) {
$tpl->cached->valid = false;
} else {
$tpl->mustCompile = true;
}
return false;
}
/**
* Call error handler for undefined method
*
* @param string $name unknown method-name
* @param array $args argument array
*
* @return mixed
* @throws SmartyException
*/
public function __call($name, $args)
{
throw new SmartyException(get_class($args[0]) . "->{$name}() undefined method");
}
}

View File

@ -1,47 +0,0 @@
<?php
/**
* Smarty Resource Plugin
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
*/
/**
* Smarty Resource Plugin
* Base implementation for resource plugins that don't compile cache
*
* @package Smarty
* @subpackage TemplateResources
*/
abstract class Smarty_Resource_Recompiled extends Smarty_Resource
{
/**
* Flag that it's an recompiled resource
*
* @var bool
*/
public $recompiled = true;
/**
* Resource does implement populateCompiledFilepath() method
*
* @var bool
*/
public $hasCompiledHandler = true;
/**
* populate Compiled Object with compiled filepath
*
* @param Smarty_Template_Compiled $compiled compiled object
* @param Smarty_Internal_Template $_template template object
*
* @return void
*/
public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template)
{
$compiled->filepath = false;
$compiled->timestamp = false;
$compiled->exists = false;
}
}

View File

@ -1,79 +0,0 @@
<?php
/**
* Smarty Resource Plugin
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
*/
/**
* Smarty Resource Plugin
* Base implementation for resource plugins that don't use the compiler
*
* @package Smarty
* @subpackage TemplateResources
*/
abstract class Smarty_Resource_Uncompiled extends Smarty_Resource
{
/**
* Flag that it's an uncompiled resource
*
* @var bool
*/
public $uncompiled = true;
/**
* Resource does implement populateCompiledFilepath() method
*
* @var bool
*/
public $hasCompiledHandler = true;
/**
* Render and output the template (without using the compiler)
*
* @param Smarty_Template_Source $source source object
* @param Smarty_Internal_Template $_template template object
*
* @throws SmartyException on failure
*/
abstract public function renderUncompiled(Smarty_Template_Source $source, Smarty_Internal_Template $_template);
/**
* populate compiled object with compiled filepath
*
* @param Smarty_Template_Compiled $compiled compiled object
* @param Smarty_Internal_Template $_template template object (is ignored)
*/
public function populateCompiledFilepath(Smarty_Template_Compiled $compiled, Smarty_Internal_Template $_template)
{
$compiled->filepath = false;
$compiled->timestamp = false;
$compiled->exists = false;
}
/**
* render compiled template code
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @throws Exception
*/
public function render($_template)
{
$level = ob_get_level();
ob_start();
try {
$this->renderUncompiled($_template->source, $_template);
return ob_get_clean();
}
catch (Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
}
}

View File

@ -1,297 +0,0 @@
<?php
/**
* Smarty Resource Data Object
* Meta Data Container for Template Files
*
* @package Smarty
* @subpackage TemplateResources
* @author Rodney Rehm
* @property string $content compiled content
*/
class Smarty_Template_Compiled extends Smarty_Template_Resource_Base
{
/**
* nocache hash
*
* @var string|null
*/
public $nocache_hash = null;
/**
* get a Compiled Object of this source
*
* @param Smarty_Internal_Template $_template template object
*
* @return Smarty_Template_Compiled compiled object
*/
static function load($_template)
{
// check runtime cache
if (!$_template->source->handler->recompiled &&
($_template->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON)
) {
$_cache_key = $_template->source->unique_resource . '#';
if ($_template->caching) {
$_cache_key .= 'caching#';
}
$_cache_key .= $_template->compile_id;
if (isset($_template->source->compileds[$_cache_key])) {
return $_template->source->compileds[$_cache_key];
}
}
$compiled = new Smarty_Template_Compiled();
if ($_template->source->handler->hasCompiledHandler) {
$_template->source->handler->populateCompiledFilepath($compiled, $_template);
} else {
$compiled->populateCompiledFilepath($_template);
}
// runtime cache
if (!$_template->source->handler->recompiled &&
($_template->smarty->resource_cache_mode & Smarty::RESOURCE_CACHE_ON)
) {
$_template->source->compileds[$_cache_key] = $compiled;
}
return $compiled;
}
/**
* populate Compiled Object with compiled filepath
*
* @param Smarty_Internal_Template $_template template object
**/
public function populateCompiledFilepath(Smarty_Internal_Template $_template)
{
$_compile_id = isset($_template->compile_id) ? preg_replace('![^\w]+!', '_', $_template->compile_id) : null;
if ($_template->source->isConfig) {
$_flag = '_' .
((int) $_template->smarty->config_read_hidden + (int) $_template->smarty->config_booleanize * 2 +
(int) $_template->smarty->config_overwrite * 4);
} else {
$_flag =
'_' . ((int) $_template->smarty->merge_compiled_includes + (int) $_template->smarty->escape_html * 2);
}
$_filepath = $_template->source->uid . $_flag;
// if use_sub_dirs, break file into directories
if ($_template->smarty->use_sub_dirs) {
$_filepath = substr($_filepath, 0, 2) . DS . substr($_filepath, 2, 2) . DS . substr($_filepath, 4, 2) . DS .
$_filepath;
}
$_compile_dir_sep = $_template->smarty->use_sub_dirs ? DS : '^';
if (isset($_compile_id)) {
$_filepath = $_compile_id . $_compile_dir_sep . $_filepath;
}
// caching token
if ($_template->caching) {
$_cache = '.cache';
} else {
$_cache = '';
}
$_compile_dir = $_template->smarty->getCompileDir();
// set basename if not specified
$_basename = $_template->source->handler->getBasename($_template->source);
if ($_basename === null) {
$_basename = basename(preg_replace('![^\w]+!', '_', $_template->source->name));
}
// separate (optional) basename by dot
if ($_basename) {
$_basename = '.' . $_basename;
}
$this->filepath = $_compile_dir . $_filepath . '.' . $_template->source->type . $_basename . $_cache . '.php';
$this->exists = is_file($this->filepath);
if (!$this->exists) {
$this->timestamp = false;
}
}
/**
* load compiled template or compile from source
*
* @param Smarty_Internal_Template $_template
*
* @throws Exception
*/
public function process(Smarty_Internal_Template $_template)
{
$_smarty_tpl = $_template;
if ($_template->source->handler->recompiled || !$_template->compiled->exists ||
$_template->smarty->force_compile || ($_template->smarty->compile_check &&
$_template->source->getTimeStamp() > $_template->compiled->getTimeStamp())
) {
$this->compileTemplateSource($_template);
$compileCheck = $_template->smarty->compile_check;
$_template->smarty->compile_check = false;
if ($_template->source->handler->recompiled) {
$level = ob_get_level();
ob_start();
try {
eval("?>" . $this->content);
}
catch (Exception $e) {
while (ob_get_level() > $level) {
ob_end_clean();
}
throw $e;
}
ob_get_clean();
$this->content = null;
} else {
$this->loadCompiledTemplate($_template);
}
$_template->smarty->compile_check = $compileCheck;
} else {
$_template->mustCompile = true;
@include($_template->compiled->filepath);
if ($_template->mustCompile) {
$this->compileTemplateSource($_template);
$compileCheck = $_template->smarty->compile_check;
$_template->smarty->compile_check = false;
$this->loadCompiledTemplate($_template);
$_template->smarty->compile_check = $compileCheck;
}
}
$_template->smarty->ext->_subTemplate->registerSubTemplates($_template);
$this->processed = true;
}
/**
* Load fresh compiled template by including the PHP file
* HHVM requires a work around because of a PHP incompatibility
*
* @param \Smarty_Internal_Template $_template
*/
private function loadCompiledTemplate(Smarty_Internal_Template $_template)
{
if (function_exists('opcache_invalidate')) {
opcache_invalidate($_template->compiled->filepath);
}
$_smarty_tpl = $_template;
if (defined('HHVM_VERSION')) {
$_template->smarty->ext->_hhvm->includeHhvm($_template, $_template->compiled->filepath);
} else {
include($_template->compiled->filepath);
}
}
/**
* render compiled template code
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @throws Exception
*/
public function render(Smarty_Internal_Template $_template)
{
if ($_template->smarty->debugging) {
$_template->smarty->_debug->start_render($_template);
}
if (!$this->processed) {
$this->process($_template);
}
if (isset($_template->cached)) {
$_template->cached->file_dependency =
array_merge($_template->cached->file_dependency, $this->file_dependency);
}
$this->getRenderedTemplateCode($_template);
if ($_template->caching && $this->has_nocache_code) {
$_template->cached->hashes[$this->nocache_hash] = true;
}
if (isset($_template->parent) && $_template->parent->_objType == 2 && !empty($_template->tpl_function)) {
$_template->parent->tpl_function = array_merge($_template->parent->tpl_function, $_template->tpl_function);
}
if ($_template->smarty->debugging) {
$_template->smarty->_debug->end_render($_template);
}
}
/**
* compile template from source
*
* @param Smarty_Internal_Template $_template
*
* @return string
* @throws Exception
*/
public function compileTemplateSource(Smarty_Internal_Template $_template)
{
$_template->source->compileds = array();
$this->file_dependency = array();
$this->tpl_function = array();
$this->includes = array();
$this->nocache_hash = null;
$this->unifunc = null;
// compile locking
if (!$_template->source->handler->recompiled) {
if ($saved_timestamp = $_template->compiled->getTimeStamp()) {
touch($_template->compiled->filepath);
}
}
// call compiler
try {
$_template->loadCompiler();
$code = $_template->compiler->compileTemplate($_template);
}
catch (Exception $e) {
// restore old timestamp in case of error
if (!$_template->source->handler->recompiled && $saved_timestamp) {
touch($_template->compiled->filepath, $saved_timestamp);
}
throw $e;
}
// compiling succeeded
if ($_template->compiler->write_compiled_code) {
// write compiled template
$this->write($_template, $code);
$code = '';
}
// release compiler object to free memory
unset($_template->compiler);
return $code;
}
/**
* Write compiled code by handler
*
* @param Smarty_Internal_Template $_template template object
* @param string $code compiled code
*
* @return boolean success
*/
public function write(Smarty_Internal_Template $_template, $code)
{
if (!$_template->source->handler->recompiled) {
if ($_template->smarty->ext->_writeFile->writeFile($this->filepath, $code, $_template->smarty) === true) {
$this->timestamp = $this->exists = is_file($this->filepath);
if ($this->exists) {
$this->timestamp = filemtime($this->filepath);
return true;
}
}
return false;
} else {
$this->content = $code;
}
$this->timestamp = time();
$this->exists = true;
return true;
}
/**
* Read compiled content from handler
*
* @param Smarty_Internal_Template $_template template object
*
* @return string content
*/
public function read(Smarty_Internal_Template $_template)
{
if (!$_template->source->handler->recompiled) {
return file_get_contents($this->filepath);
}
return isset($this->content) ? $this->content : false;
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Smarty Config Source Plugin
*
* @package Smarty
* @subpackage TemplateResources
* @author Uwe Tews
*/
/**
* Smarty Connfig Resource Data Object
* Meta Data Container for Template Files
*
* @package Smarty
* @subpackage TemplateResources
* @author Uwe Tews
*
*/
class Smarty_Template_Config extends Smarty_Template_Source
{
/**
* array of section names, single section or null
*
* @var null|string|array
*/
public $config_sections = null;
/**
* scope into which the config variables shall be loaded
*
* @var string
*/
public $scope = 'local';
/**
* Flag that source is a config file
*
* @var bool
*/
public $isConfig = true;
/**
* create Source Object container
*
* @param Smarty_Resource $handler Resource Handler this source object communicates with
* @param Smarty $smarty Smarty instance this source object belongs to
* @param string $resource full template_resource
* @param string $type type of resource
* @param string $name resource name
*/
public function __construct(Smarty_Resource $handler, Smarty $smarty, $resource, $type, $name)
{
// must clone handler as we change class names
$this->handler = clone $handler; // Note: prone to circular references
$this->handler->compiler_class = 'Smarty_Internal_Config_File_Compiler';
$this->handler->template_lexer_class = 'Smarty_Internal_Configfilelexer';
$this->handler->template_parser_class = 'Smarty_Internal_Configfileparser';
$this->resource = $resource;
$this->type = $type;
$this->name = $name;
$this->smarty = $smarty;
}
/**
* initialize Source Object for given resource
* Either [$_template] or [$smarty, $template_resource] must be specified
*
* @param Smarty_Internal_Template $_template template object
* @param Smarty $smarty smarty object
* @param string $template_resource resource identifier
*
* @return Smarty_Template_Config Source Object
* @throws SmartyException
*/
public static function load(Smarty_Internal_Template $_template = null, Smarty $smarty = null, $template_resource = null)
{
static $_incompatible_resources = array('extends' => true, 'php' => true);
$template_resource = $_template->template_resource;
if (empty($template_resource)) {
throw new SmartyException('Missing config name');
}
// parse resource_name, load resource handler
list($name, $type) = Smarty_Resource::parseResourceName($template_resource, $_template->smarty->default_config_type);
// make sure configs are not loaded via anything smarty can't handle
if (isset($_incompatible_resources[$type])) {
throw new SmartyException ("Unable to use resource '{$type}' for config");
}
$resource = Smarty_Resource::load($_template->smarty, $type);
$source = new Smarty_Template_Config($resource, $_template->smarty, $template_resource, $type, $name);
$resource->populate($source, $_template);
if (!$source->exists && isset($_template->smarty->default_config_handler_func)) {
Smarty_Internal_Method_RegisterDefaultTemplateHandler::_getDefaultTemplate($source);
}
$source->unique_resource = $resource->buildUniqueResourceName($_template->smarty, $name, true);
return $source;
}
}

View File

@ -8,6 +8,24 @@ To see the files changed for a given bug, go to https://github.com/bshaffer/oaut
To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1 To get the diff between two versions, go to https://github.com/bshaffer/oauth2-server-php/compare/v1.0...v1.1
To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-server-php/commit/XXX where XXX is the change hash
* 1.10.0 (2017-12-14)
PR: https://github.com/bshaffer/oauth2-server-php/pull/889
* #795 - [feature] added protected createPayload method to allow easier customization of JWT payload
* #807 - [refactor] simplifies UserInfoController constructor
* #814 - [docs] Adds https to README link
* #827 - [testing] Explicitly pulls in phpunit 4
* #828 - [docs] PHPDoc improvements and type hinting of variables.
* #829 - [bug] Fix CORS issue for revoking and requesting an access token
* #869 - [testing] Remove php 5.3 from travis and use vendored phpunit
* #834 - [feature] use random_bytes if available
* #851 - [docs] Fix PHPDoc
* #872 - [bug] Fix count() error on PHP 7.2
* #873 - [testing] adds php 7.2 to travis
* #794 - [docs] Fix typo in composer.json
* #885 - [testing] Use PHPUnit\Framework\TestCase instead of PHPUnit_Framework_TestCase
* 1.9.0 (2016-01-06) * 1.9.0 (2016-01-06)
PR: https://github.com/bshaffer/oauth2-server-php/pull/788 PR: https://github.com/bshaffer/oauth2-server-php/pull/788
@ -87,7 +105,7 @@ To get the diff for a specific change, go to https://github.com/bshaffer/oauth2-
* bug #346 Fixes open_basedir warning * bug #346 Fixes open_basedir warning
* bug #351 Adds OpenID Connect support * bug #351 Adds OpenID Connect support
* bug #355 Adds php 5.6 and HHVM to travis.ci testing * bug #355 Adds php 5.6 and HHVM to travis.ci testing
* [BC] bug #358 Adds `getQuerystringIdentifier()` to the GrantType interface * [BC] bug #358 Adds `getQueryStringIdentifier()` to the GrantType interface
* bug #363 Encryption\JWT - Allows for subclassing JWT Headers * bug #363 Encryption\JWT - Allows for subclassing JWT Headers
* bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional * bug #349 Bearer Tokens - adds requestHasToken method for when access tokens are optional
* bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected * bug #301 Encryption\JWT - fixes urlSafeB64Encode(): ensures newlines are replaced as expected

View File

@ -5,4 +5,4 @@ oauth2-server-php
[![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php) [![Total Downloads](https://poser.pugx.org/bshaffer/oauth2-server-php/downloads.png)](https://packagist.org/packages/bshaffer/oauth2-server-php)
View the [complete documentation](http://bshaffer.github.io/oauth2-server-php-docs/) View the [complete documentation](https://bshaffer.github.io/oauth2-server-php-docs/)

View File

@ -19,6 +19,7 @@
"php":">=5.3.9" "php":">=5.3.9"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.0",
"aws/aws-sdk-php": "~2.8", "aws/aws-sdk-php": "~2.8",
"firebase/php-jwt": "~2.2", "firebase/php-jwt": "~2.2",
"predis/predis": "dev-master", "predis/predis": "dev-master",
@ -29,6 +30,7 @@
"predis/predis": "Required to use Redis storage", "predis/predis": "Required to use Redis storage",
"thobbs/phpcassa": "Required to use Cassandra storage", "thobbs/phpcassa": "Required to use Cassandra storage",
"aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage", "aws/aws-sdk-php": "~2.8 is required to use DynamoDB storage",
"firebase/php-jwt": "~1.1 is required to use MondoDB storage" "firebase/php-jwt": "~2.2 is required to use JWT features",
"mongodb/mongodb": "^1.1 is required to use MongoDB storage"
} }
} }

View File

@ -10,8 +10,14 @@ namespace OAuth2;
*/ */
class Autoloader class Autoloader
{ {
/**
* @var string
*/
private $dir; private $dir;
/**
* @param string $dir
*/
public function __construct($dir = null) public function __construct($dir = null)
{ {
if (is_null($dir)) { if (is_null($dir)) {
@ -19,6 +25,7 @@ class Autoloader
} }
$this->dir = $dir; $this->dir = $dir;
} }
/** /**
* Registers OAuth2\Autoloader as an SPL autoloader. * Registers OAuth2\Autoloader as an SPL autoloader.
*/ */
@ -31,9 +38,8 @@ class Autoloader
/** /**
* Handles autoloading of classes. * Handles autoloading of classes.
* *
* @param string $class A class name. * @param string $class - A class name.
* * @return boolean - Returns true if the class has been loaded
* @return boolean Returns true if the class has been loaded
*/ */
public function autoload($class) public function autoload($class)
{ {

View File

@ -10,6 +10,19 @@ use OAuth2\ResponseInterface;
*/ */
interface ClientAssertionTypeInterface interface ClientAssertionTypeInterface
{ {
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return mixed
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response); public function validateRequest(RequestInterface $request, ResponseInterface $response);
/**
* Get the client id
*
* @return mixed
*/
public function getClientId(); public function getClientId();
} }

View File

@ -5,6 +5,7 @@ namespace OAuth2\ClientAssertionType;
use OAuth2\Storage\ClientCredentialsInterface; use OAuth2\Storage\ClientCredentialsInterface;
use OAuth2\RequestInterface; use OAuth2\RequestInterface;
use OAuth2\ResponseInterface; use OAuth2\ResponseInterface;
use LogicException;
/** /**
* Validate a client via Http Basic authentication * Validate a client via Http Basic authentication
@ -19,14 +20,16 @@ class HttpBasic implements ClientAssertionTypeInterface
protected $config; protected $config;
/** /**
* @param OAuth2\Storage\ClientCredentialsInterface $clientStorage REQUIRED Storage class for retrieving client credentials information * Config array $config should look as follows:
* @param array $config OPTIONAL Configuration options for the server * @code
* <code> * $config = array(
* $config = array( * 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header
* 'allow_credentials_in_request_body' => true, // whether to look for credentials in the POST body in addition to the Authorize HTTP Header * 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated
* 'allow_public_clients' => true // if true, "public clients" (clients without a secret) may be authenticated * );
* ); * @endcode
* </code> *
* @param ClientCredentialsInterface $storage Storage
* @param array $config Configuration options for the server
*/ */
public function __construct(ClientCredentialsInterface $storage, array $config = array()) public function __construct(ClientCredentialsInterface $storage, array $config = array())
{ {
@ -37,6 +40,14 @@ class HttpBasic implements ClientAssertionTypeInterface
), $config); ), $config);
} }
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed
* @throws LogicException
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response) public function validateRequest(RequestInterface $request, ResponseInterface $response)
{ {
if (!$clientData = $this->getClientCredentials($request, $response)) { if (!$clientData = $this->getClientCredentials($request, $response)) {
@ -44,7 +55,7 @@ class HttpBasic implements ClientAssertionTypeInterface
} }
if (!isset($clientData['client_id'])) { if (!isset($clientData['client_id'])) {
throw new \LogicException('the clientData array must have "client_id" set'); throw new LogicException('the clientData array must have "client_id" set');
} }
if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') { if (!isset($clientData['client_secret']) || $clientData['client_secret'] == '') {
@ -70,6 +81,11 @@ class HttpBasic implements ClientAssertionTypeInterface
return true; return true;
} }
/**
* Get the client id
*
* @return mixed
*/
public function getClientId() public function getClientId()
{ {
return $this->clientData['client_id']; return $this->clientData['client_id'];
@ -82,13 +98,14 @@ class HttpBasic implements ClientAssertionTypeInterface
* According to the spec (draft 20), the client_id can be provided in * According to the spec (draft 20), the client_id can be provided in
* the Basic Authorization header (recommended) or via GET/POST. * the Basic Authorization header (recommended) or via GET/POST.
* *
* @return * @param RequestInterface $request
* A list containing the client identifier and password, for example * @param ResponseInterface $response
* @return array|null A list containing the client identifier and password, for example:
* @code * @code
* return array( * return array(
* "client_id" => CLIENT_ID, // REQUIRED the client id * "client_id" => CLIENT_ID, // REQUIRED the client id
* "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients) * "client_secret" => CLIENT_SECRET, // OPTIONAL the client secret (may be omitted for public clients)
* ); * );
* @endcode * @endcode
* *
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1 * @see http://tools.ietf.org/html/rfc6749#section-2.3.1
@ -108,7 +125,6 @@ class HttpBasic implements ClientAssertionTypeInterface
* client_secret can be null if the client's password is an empty string * client_secret can be null if the client's password is an empty string
* @see http://tools.ietf.org/html/rfc6749#section-2.3.1 * @see http://tools.ietf.org/html/rfc6749#section-2.3.1
*/ */
return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret')); return array('client_id' => $request->request('client_id'), 'client_secret' => $request->request('client_secret'));
} }
} }

View File

@ -7,37 +7,76 @@ use OAuth2\ScopeInterface;
use OAuth2\RequestInterface; use OAuth2\RequestInterface;
use OAuth2\ResponseInterface; use OAuth2\ResponseInterface;
use OAuth2\Scope; use OAuth2\Scope;
use InvalidArgumentException;
/** /**
* @see OAuth2\Controller\AuthorizeControllerInterface * @see AuthorizeControllerInterface
*/ */
class AuthorizeController implements AuthorizeControllerInterface class AuthorizeController implements AuthorizeControllerInterface
{ {
/**
* @var string
*/
private $scope; private $scope;
/**
* @var int
*/
private $state; private $state;
/**
* @var mixed
*/
private $client_id; private $client_id;
/**
* @var string
*/
private $redirect_uri; private $redirect_uri;
/**
* The response type
*
* @var string
*/
private $response_type; private $response_type;
/**
* @var ClientInterface
*/
protected $clientStorage; protected $clientStorage;
/**
* @var array
*/
protected $responseTypes; protected $responseTypes;
/**
* @var array
*/
protected $config; protected $config;
/**
* @var ScopeInterface
*/
protected $scopeUtil; protected $scopeUtil;
/** /**
* @param OAuth2\Storage\ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information * Constructor
* @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array *
* keys are "code" and "token" * @param ClientInterface $clientStorage REQUIRED Instance of OAuth2\Storage\ClientInterface to retrieve client information
* @param array $config OPTIONAL Configuration options for the server * @param array $responseTypes OPTIONAL Array of OAuth2\ResponseType\ResponseTypeInterface objects. Valid array
* <code> * keys are "code" and "token"
* $config = array( * @param array $config OPTIONAL Configuration options for the server:
* 'allow_implicit' => false, // if the controller should allow the "implicit" grant type * @param ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope
* 'enforce_state' => true // if the controller should require the "state" parameter * @code
* 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter * $config = array(
* 'redirect_status_code' => 302, // HTTP status code to use for redirect responses * 'allow_implicit' => false, // if the controller should allow the "implicit" grant type
* ); * 'enforce_state' => true // if the controller should require the "state" parameter
* </code> * 'require_exact_redirect_uri' => true, // if the controller should require an exact match on the "redirect_uri" parameter
* @param OAuth2\ScopeInterface $scopeUtil OPTIONAL Instance of OAuth2\ScopeInterface to validate the requested scope * 'redirect_status_code' => 302, // HTTP status code to use for redirect responses
* );
* @endcode
*/ */
public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null) public function __construct(ClientInterface $clientStorage, array $responseTypes = array(), array $config = array(), ScopeInterface $scopeUtil = null)
{ {
@ -56,10 +95,20 @@ class AuthorizeController implements AuthorizeControllerInterface
$this->scopeUtil = $scopeUtil; $this->scopeUtil = $scopeUtil;
} }
/**
* Handle the authorization request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param boolean $is_authorized
* @param mixed $user_id
* @return mixed|void
* @throws InvalidArgumentException
*/
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null) public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null)
{ {
if (!is_bool($is_authorized)) { if (!is_bool($is_authorized)) {
throw new \InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.'); throw new InvalidArgumentException('Argument "is_authorized" must be a boolean. This method must know if the user has granted access to the client.');
} }
// We repeat this, because we need to re-validate. The request could be POSTed // We repeat this, because we need to re-validate. The request could be POSTed
@ -101,6 +150,14 @@ class AuthorizeController implements AuthorizeControllerInterface
$response->setRedirect($this->config['redirect_status_code'], $uri); $response->setRedirect($this->config['redirect_status_code'], $uri);
} }
/**
* Set not authorized response
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param string $redirect_uri
* @param mixed $user_id
*/
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
{ {
$error = 'access_denied'; $error = 'access_denied';
@ -108,9 +165,16 @@ class AuthorizeController implements AuthorizeControllerInterface
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message); $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->state, $error, $error_message);
} }
/* /**
* We have made this protected so this class can be extended to add/modify * We have made this protected so this class can be extended to add/modify
* these parameters * these parameters
*
* @TODO: add dependency injection for the parameters in this method
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param mixed $user_id
* @return array
*/ */
protected function buildAuthorizeParameters($request, $response, $user_id) protected function buildAuthorizeParameters($request, $response, $user_id)
{ {
@ -127,6 +191,8 @@ class AuthorizeController implements AuthorizeControllerInterface
} }
/** /**
* Validate the OAuth request
*
* @param RequestInterface $request * @param RequestInterface $request
* @param ResponseInterface $response * @param ResponseInterface $response
* @return bool * @return bool
@ -186,7 +252,7 @@ class AuthorizeController implements AuthorizeControllerInterface
$redirect_uri = $registered_redirect_uri; $redirect_uri = $registered_redirect_uri;
} }
// Select the redirect URI // Select the response type
$response_type = $request->query('response_type', $request->request('response_type')); $response_type = $request->query('response_type', $request->request('response_type'));
// for multiple-valued response types - make them alphabetical // for multiple-valued response types - make them alphabetical
@ -281,10 +347,10 @@ class AuthorizeController implements AuthorizeControllerInterface
/** /**
* Build the absolute URI based on supplied URI and parameters. * Build the absolute URI based on supplied URI and parameters.
* *
* @param $uri An absolute URI. * @param string $uri An absolute URI.
* @param $params Parameters to be append as GET. * @param array $params Parameters to be append as GET.
* *
* @return * @return string
* An absolute URI with supplied parameters. * An absolute URI with supplied parameters.
* *
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
@ -302,9 +368,9 @@ class AuthorizeController implements AuthorizeControllerInterface
} }
} }
// Put humpty dumpty back together // Put the uri back together
return return
((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "") ((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
. ((isset($parse_url["user"])) ? $parse_url["user"] . ((isset($parse_url["user"])) ? $parse_url["user"]
. ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "") . ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "")
. ((isset($parse_url["host"])) ? $parse_url["host"] : "") . ((isset($parse_url["host"])) ? $parse_url["host"] : "")
@ -326,10 +392,10 @@ class AuthorizeController implements AuthorizeControllerInterface
/** /**
* Internal method for validating redirect URI supplied * Internal method for validating redirect URI supplied
* *
* @param string $inputUri The submitted URI to be validated * @param string $inputUri The submitted URI to be validated
* @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to * @param string $registeredUriString The allowed URI(s) to validate against. Can be a space-delimited string of URIs to
* allow for multiple URIs * allow for multiple URIs
* * @return bool
* @see http://tools.ietf.org/html/rfc6749#section-3.1.2 * @see http://tools.ietf.org/html/rfc6749#section-3.1.2
*/ */
protected function validateRedirectUri($inputUri, $registeredUriString) protected function validateRedirectUri($inputUri, $registeredUriString)
@ -363,29 +429,50 @@ class AuthorizeController implements AuthorizeControllerInterface
} }
/** /**
* Convenience methods to access the parameters derived from the validated request * Convenience method to access the scope
*
* @return string
*/ */
public function getScope() public function getScope()
{ {
return $this->scope; return $this->scope;
} }
/**
* Convenience method to access the state
*
* @return int
*/
public function getState() public function getState()
{ {
return $this->state; return $this->state;
} }
/**
* Convenience method to access the client id
*
* @return mixed
*/
public function getClientId() public function getClientId()
{ {
return $this->client_id; return $this->client_id;
} }
/**
* Convenience method to access the redirect url
*
* @return string
*/
public function getRedirectUri() public function getRedirectUri()
{ {
return $this->redirect_uri; return $this->redirect_uri;
} }
/**
* Convenience method to access the response type
*
* @return string
*/
public function getResponseType() public function getResponseType()
{ {
return $this->response_type; return $this->response_type;

View File

@ -11,17 +11,18 @@ use OAuth2\ResponseInterface;
* authorization directly, this controller ensures the request is valid, but * authorization directly, this controller ensures the request is valid, but
* requires the application to determine the value of $is_authorized * requires the application to determine the value of $is_authorized
* *
* ex: * @code
* > $user_id = $this->somehowDetermineUserId(); * $user_id = $this->somehowDetermineUserId();
* > $is_authorized = $this->somehowDetermineUserAuthorization(); * $is_authorized = $this->somehowDetermineUserAuthorization();
* > $response = new OAuth2\Response(); * $response = new OAuth2\Response();
* > $authorizeController->handleAuthorizeRequest( * $authorizeController->handleAuthorizeRequest(
* > OAuth2\Request::createFromGlobals(), * OAuth2\Request::createFromGlobals(),
* > $response, * $response,
* > $is_authorized, * $is_authorized,
* > $user_id); * $user_id
* > $response->send(); * );
* * $response->send();
* @endcode
*/ */
interface AuthorizeControllerInterface interface AuthorizeControllerInterface
{ {
@ -37,7 +38,21 @@ interface AuthorizeControllerInterface
const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code'; const RESPONSE_TYPE_AUTHORIZATION_CODE = 'code';
const RESPONSE_TYPE_ACCESS_TOKEN = 'token'; const RESPONSE_TYPE_ACCESS_TOKEN = 'token';
/**
* Handle the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param $is_authorized
* @param null $user_id
* @return mixed
*/
public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null); public function handleAuthorizeRequest(RequestInterface $request, ResponseInterface $response, $is_authorized, $user_id = null);
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
*/
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response); public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response);
} }

View File

@ -10,17 +10,43 @@ use OAuth2\ResponseInterface;
use OAuth2\Scope; use OAuth2\Scope;
/** /**
* @see OAuth2\Controller\ResourceControllerInterface * @see ResourceControllerInterface
*/ */
class ResourceController implements ResourceControllerInterface class ResourceController implements ResourceControllerInterface
{ {
/**
* @var array
*/
private $token; private $token;
/**
* @var TokenTypeInterface
*/
protected $tokenType; protected $tokenType;
/**
* @var AccessTokenInterface
*/
protected $tokenStorage; protected $tokenStorage;
/**
* @var array
*/
protected $config; protected $config;
/**
* @var ScopeInterface
*/
protected $scopeUtil; protected $scopeUtil;
/**
* Constructor
*
* @param TokenTypeInterface $tokenType
* @param AccessTokenInterface $tokenStorage
* @param array $config
* @param ScopeInterface $scopeUtil
*/
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null) public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, $config = array(), ScopeInterface $scopeUtil = null)
{ {
$this->tokenType = $tokenType; $this->tokenType = $tokenType;
@ -36,6 +62,14 @@ class ResourceController implements ResourceControllerInterface
$this->scopeUtil = $scopeUtil; $this->scopeUtil = $scopeUtil;
} }
/**
* Verify the resource request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param null $scope
* @return bool
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null) public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null)
{ {
$token = $this->getAccessTokenData($request, $response); $token = $this->getAccessTokenData($request, $response);
@ -71,6 +105,13 @@ class ResourceController implements ResourceControllerInterface
return (bool) $token; return (bool) $token;
} }
/**
* Get access token data.
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return array|null
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response) public function getAccessTokenData(RequestInterface $request, ResponseInterface $response)
{ {
// Get the token parameter // Get the token parameter
@ -103,7 +144,11 @@ class ResourceController implements ResourceControllerInterface
return null; return null;
} }
// convenience method to allow retrieval of the token /**
* convenience method to allow retrieval of the token.
*
* @return array
*/
public function getToken() public function getToken()
{ {
return $this->token; return $this->token;

View File

@ -10,17 +10,32 @@ use OAuth2\ResponseInterface;
* call verifyResourceRequest in order to determine if the request * call verifyResourceRequest in order to determine if the request
* contains a valid token. * contains a valid token.
* *
* ex: * @code
* > if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) { * if (!$resourceController->verifyResourceRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response())) {
* > $response->send(); // authorization failed * $response->send(); // authorization failed
* > die(); * die();
* > } * }
* > return json_encode($resource); // valid token! Send the stuff! * return json_encode($resource); // valid token! Send the stuff!
* * @endcode
*/ */
interface ResourceControllerInterface interface ResourceControllerInterface
{ {
/**
* Verify the resource request
*
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @param string $scope
* @return mixed
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null); public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response, $scope = null);
/**
* Get access token data.
*
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response); public function getAccessTokenData(RequestInterface $request, ResponseInterface $response);
} }

View File

@ -10,9 +10,12 @@ use OAuth2\Scope;
use OAuth2\Storage\ClientInterface; use OAuth2\Storage\ClientInterface;
use OAuth2\RequestInterface; use OAuth2\RequestInterface;
use OAuth2\ResponseInterface; use OAuth2\ResponseInterface;
use InvalidArgumentException;
use LogicException;
use RuntimeException;
/** /**
* @see \OAuth2\Controller\TokenControllerInterface * @see TokenControllerInterface
*/ */
class TokenController implements TokenControllerInterface class TokenController implements TokenControllerInterface
{ {
@ -22,7 +25,7 @@ class TokenController implements TokenControllerInterface
protected $accessToken; protected $accessToken;
/** /**
* @var array * @var array<GrantTypeInterface>
*/ */
protected $grantTypes; protected $grantTypes;
@ -32,7 +35,7 @@ class TokenController implements TokenControllerInterface
protected $clientAssertionType; protected $clientAssertionType;
/** /**
* @var Scope|ScopeInterface * @var ScopeInterface
*/ */
protected $scopeUtil; protected $scopeUtil;
@ -41,12 +44,22 @@ class TokenController implements TokenControllerInterface
*/ */
protected $clientStorage; protected $clientStorage;
/**
* Constructor
*
* @param AccessTokenInterface $accessToken
* @param ClientInterface $clientStorage
* @param array $grantTypes
* @param ClientAssertionTypeInterface $clientAssertionType
* @param ScopeInterface $scopeUtil
* @throws InvalidArgumentException
*/
public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null) public function __construct(AccessTokenInterface $accessToken, ClientInterface $clientStorage, array $grantTypes = array(), ClientAssertionTypeInterface $clientAssertionType = null, ScopeInterface $scopeUtil = null)
{ {
if (is_null($clientAssertionType)) { if (is_null($clientAssertionType)) {
foreach ($grantTypes as $grantType) { foreach ($grantTypes as $grantType) {
if (!$grantType instanceof ClientAssertionTypeInterface) { if (!$grantType instanceof ClientAssertionTypeInterface) {
throw new \InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface'); throw new InvalidArgumentException('You must supply an instance of OAuth2\ClientAssertionType\ClientAssertionTypeInterface or only use grant types which implement OAuth2\ClientAssertionType\ClientAssertionTypeInterface');
} }
} }
} }
@ -63,6 +76,12 @@ class TokenController implements TokenControllerInterface
$this->scopeUtil = $scopeUtil; $this->scopeUtil = $scopeUtil;
} }
/**
* Handle the token request.
*
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
*/
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response) public function handleTokenRequest(RequestInterface $request, ResponseInterface $response)
{ {
if ($token = $this->grantAccessToken($request, $response)) { if ($token = $this->grantAccessToken($request, $response)) {
@ -83,8 +102,10 @@ class TokenController implements TokenControllerInterface
* This would be called from the "/token" endpoint as defined in the spec. * This would be called from the "/token" endpoint as defined in the spec.
* You can call your endpoint whatever you want. * You can call your endpoint whatever you want.
* *
* @param RequestInterface $request Request object to grant access token * @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response * @param ResponseInterface $response - Response object
*
* @return bool|null|array
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @throws \LogicException * @throws \LogicException
@ -97,9 +118,15 @@ class TokenController implements TokenControllerInterface
*/ */
public function grantAccessToken(RequestInterface $request, ResponseInterface $response) public function grantAccessToken(RequestInterface $request, ResponseInterface $response)
{ {
if (strtolower($request->server('REQUEST_METHOD')) != 'post') { if (strtolower($request->server('REQUEST_METHOD')) === 'options') {
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
if (strtolower($request->server('REQUEST_METHOD')) !== 'post') {
$response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2'); $response->setError(405, 'invalid_request', 'The request method must be POST when requesting an access token', '#section-3.2');
$response->addHttpHeaders(array('Allow' => 'POST')); $response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null; return null;
} }
@ -121,6 +148,7 @@ class TokenController implements TokenControllerInterface
return null; return null;
} }
/** @var GrantTypeInterface $grantType */
$grantType = $this->grantTypes[$grantTypeIdentifier]; $grantType = $this->grantTypes[$grantTypeIdentifier];
/** /**
@ -128,8 +156,8 @@ class TokenController implements TokenControllerInterface
* ClientAssertionTypes allow for grant types which also assert the client data * ClientAssertionTypes allow for grant types which also assert the client data
* in which case ClientAssertion is handled in the validateRequest method * in which case ClientAssertion is handled in the validateRequest method
* *
* @see OAuth2\GrantType\JWTBearer * @see \OAuth2\GrantType\JWTBearer
* @see OAuth2\GrantType\ClientCredentials * @see \OAuth2\GrantType\ClientCredentials
*/ */
if (!$grantType instanceof ClientAssertionTypeInterface) { if (!$grantType instanceof ClientAssertionTypeInterface) {
if (!$this->clientAssertionType->validateRequest($request, $response)) { if (!$this->clientAssertionType->validateRequest($request, $response)) {
@ -178,7 +206,6 @@ class TokenController implements TokenControllerInterface
* *
* @see http://tools.ietf.org/html/rfc6749#section-3.3 * @see http://tools.ietf.org/html/rfc6749#section-3.3
*/ */
$requestedScope = $this->scopeUtil->getScopeFromRequest($request); $requestedScope = $this->scopeUtil->getScopeFromRequest($request);
$availableScope = $grantType->getScope(); $availableScope = $grantType->getScope();
@ -225,20 +252,24 @@ class TokenController implements TokenControllerInterface
} }
/** /**
* addGrantType * Add grant type
* *
* @param GrantTypeInterface $grantType the grant type to add for the specified identifier * @param GrantTypeInterface $grantType - the grant type to add for the specified identifier
* @param string $identifier a string passed in as "grant_type" in the response that will call this grantType * @param string|null $identifier - a string passed in as "grant_type" in the response that will call this grantType
*/ */
public function addGrantType(GrantTypeInterface $grantType, $identifier = null) public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
{ {
if (is_null($identifier) || is_numeric($identifier)) { if (is_null($identifier) || is_numeric($identifier)) {
$identifier = $grantType->getQuerystringIdentifier(); $identifier = $grantType->getQueryStringIdentifier();
} }
$this->grantTypes[$identifier] = $grantType; $this->grantTypes[$identifier] = $grantType;
} }
/**
* @param RequestInterface $request
* @param ResponseInterface $response
*/
public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response) public function handleRevokeRequest(RequestInterface $request, ResponseInterface $response)
{ {
if ($this->revokeToken($request, $response)) { if ($this->revokeToken($request, $response)) {
@ -257,13 +288,20 @@ class TokenController implements TokenControllerInterface
* *
* @param RequestInterface $request * @param RequestInterface $request
* @param ResponseInterface $response * @param ResponseInterface $response
* @throws RuntimeException
* @return bool|null * @return bool|null
*/ */
public function revokeToken(RequestInterface $request, ResponseInterface $response) public function revokeToken(RequestInterface $request, ResponseInterface $response)
{ {
if (strtolower($request->server('REQUEST_METHOD')) != 'post') { if (strtolower($request->server('REQUEST_METHOD')) === 'options') {
$response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null;
}
if (strtolower($request->server('REQUEST_METHOD')) !== 'post') {
$response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2'); $response->setError(405, 'invalid_request', 'The request method must be POST when revoking an access token', '#section-3.2');
$response->addHttpHeaders(array('Allow' => 'POST')); $response->addHttpHeaders(array('Allow' => 'POST, OPTIONS'));
return null; return null;
} }
@ -285,7 +323,7 @@ class TokenController implements TokenControllerInterface
// @todo remove this check for v2.0 // @todo remove this check for v2.0
if (!method_exists($this->accessToken, 'revokeToken')) { if (!method_exists($this->accessToken, 'revokeToken')) {
$class = get_class($this->accessToken); $class = get_class($this->accessToken);
throw new \RuntimeException("AccessToken {$class} does not implement required revokeToken method"); throw new RuntimeException("AccessToken {$class} does not implement required revokeToken method");
} }
$this->accessToken->revokeToken($token, $token_type_hint); $this->accessToken->revokeToken($token, $token_type_hint);

View File

@ -10,23 +10,30 @@ use OAuth2\ResponseInterface;
* it is called to handle all grant types the application supports. * it is called to handle all grant types the application supports.
* It also validates the client's credentials * It also validates the client's credentials
* *
* ex: * @code
* > $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response()); * $tokenController->handleTokenRequest(OAuth2\Request::createFromGlobals(), $response = new OAuth2\Response());
* > $response->send(); * $response->send();
* * @endcode
*/ */
interface TokenControllerInterface interface TokenControllerInterface
{ {
/** /**
* handleTokenRequest * Handle the token request
*
* @param $request
* OAuth2\RequestInterface - The current http request
* @param $response
* OAuth2\ResponseInterface - An instance of OAuth2\ResponseInterface to contain the response data
* *
* @param RequestInterface $request - The current http request
* @param ResponseInterface $response - An instance of OAuth2\ResponseInterface to contain the response data
*/ */
public function handleTokenRequest(RequestInterface $request, ResponseInterface $response); public function handleTokenRequest(RequestInterface $request, ResponseInterface $response);
/**
* Grant or deny a requested access token.
* This would be called from the "/token" endpoint as defined in the spec.
* You can call your endpoint whatever you want.
*
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
*
* @return mixed
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response); public function grantAccessToken(RequestInterface $request, ResponseInterface $response);
} }

View File

@ -4,8 +4,31 @@ namespace OAuth2\Encryption;
interface EncryptionInterface interface EncryptionInterface
{ {
/**
* @param $payload
* @param $key
* @param null $algorithm
* @return mixed
*/
public function encode($payload, $key, $algorithm = null); public function encode($payload, $key, $algorithm = null);
/**
* @param $payload
* @param $key
* @param null $algorithm
* @return mixed
*/
public function decode($payload, $key, $algorithm = null); public function decode($payload, $key, $algorithm = null);
/**
* @param $data
* @return mixed
*/
public function urlSafeB64Encode($data); public function urlSafeB64Encode($data);
/**
* @param $b64
* @return mixed
*/
public function urlSafeB64Decode($b64); public function urlSafeB64Decode($b64);
} }

View File

@ -2,12 +2,21 @@
namespace OAuth2\Encryption; namespace OAuth2\Encryption;
use Exception;
use InvalidArgumentException;
/** /**
* @link https://github.com/F21/jwt * @link https://github.com/F21/jwt
* @author F21 * @author F21
*/ */
class Jwt implements EncryptionInterface class Jwt implements EncryptionInterface
{ {
/**
* @param $payload
* @param $key
* @param string $algo
* @return string
*/
public function encode($payload, $key, $algo = 'HS256') public function encode($payload, $key, $algo = 'HS256')
{ {
$header = $this->generateJwtHeader($payload, $algo); $header = $this->generateJwtHeader($payload, $algo);
@ -25,6 +34,12 @@ class Jwt implements EncryptionInterface
return implode('.', $segments); return implode('.', $segments);
} }
/**
* @param string $jwt
* @param null $key
* @param array|bool $allowedAlgorithms
* @return bool|mixed
*/
public function decode($jwt, $key = null, $allowedAlgorithms = true) public function decode($jwt, $key = null, $allowedAlgorithms = true)
{ {
if (!strpos($jwt, '.')) { if (!strpos($jwt, '.')) {
@ -67,6 +82,14 @@ class Jwt implements EncryptionInterface
return $payload; return $payload;
} }
/**
* @param $signature
* @param $input
* @param $key
* @param string $algo
* @return bool
* @throws InvalidArgumentException
*/
private function verifySignature($signature, $input, $key, $algo = 'HS256') private function verifySignature($signature, $input, $key, $algo = 'HS256')
{ {
// use constants when possible, for HipHop support // use constants when possible, for HipHop support
@ -89,10 +112,17 @@ class Jwt implements EncryptionInterface
return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1; return @openssl_verify($input, $signature, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512') === 1;
default: default:
throw new \InvalidArgumentException("Unsupported or invalid signing algorithm."); throw new InvalidArgumentException("Unsupported or invalid signing algorithm.");
} }
} }
/**
* @param $input
* @param $key
* @param string $algo
* @return string
* @throws Exception
*/
private function sign($input, $key, $algo = 'HS256') private function sign($input, $key, $algo = 'HS256')
{ {
switch ($algo) { switch ($algo) {
@ -115,19 +145,30 @@ class Jwt implements EncryptionInterface
return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512'); return $this->generateRSASignature($input, $key, defined('OPENSSL_ALGO_SHA512') ? OPENSSL_ALGO_SHA512 : 'sha512');
default: default:
throw new \Exception("Unsupported or invalid signing algorithm."); throw new Exception("Unsupported or invalid signing algorithm.");
} }
} }
/**
* @param $input
* @param $key
* @param string $algo
* @return mixed
* @throws Exception
*/
private function generateRSASignature($input, $key, $algo) private function generateRSASignature($input, $key, $algo)
{ {
if (!openssl_sign($input, $signature, $key, $algo)) { if (!openssl_sign($input, $signature, $key, $algo)) {
throw new \Exception("Unable to sign data."); throw new Exception("Unable to sign data.");
} }
return $signature; return $signature;
} }
/**
* @param string $data
* @return string
*/
public function urlSafeB64Encode($data) public function urlSafeB64Encode($data)
{ {
$b64 = base64_encode($data); $b64 = base64_encode($data);
@ -138,6 +179,10 @@ class Jwt implements EncryptionInterface
return $b64; return $b64;
} }
/**
* @param string $b64
* @return mixed|string
*/
public function urlSafeB64Decode($b64) public function urlSafeB64Decode($b64)
{ {
$b64 = str_replace(array('-', '_'), $b64 = str_replace(array('-', '_'),
@ -158,6 +203,11 @@ class Jwt implements EncryptionInterface
); );
} }
/**
* @param string $a
* @param string $b
* @return bool
*/
protected function hash_equals($a, $b) protected function hash_equals($a, $b)
{ {
if (function_exists('hash_equals')) { if (function_exists('hash_equals')) {
@ -170,4 +220,4 @@ class Jwt implements EncryptionInterface
return $diff === 0; return $diff === 0;
} }
} }

View File

@ -6,29 +6,47 @@ use OAuth2\Storage\AuthorizationCodeInterface;
use OAuth2\ResponseType\AccessTokenInterface; use OAuth2\ResponseType\AccessTokenInterface;
use OAuth2\RequestInterface; use OAuth2\RequestInterface;
use OAuth2\ResponseInterface; use OAuth2\ResponseInterface;
use Exception;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class AuthorizationCode implements GrantTypeInterface class AuthorizationCode implements GrantTypeInterface
{ {
/**
* @var AuthorizationCodeInterface
*/
protected $storage; protected $storage;
/**
* @var array
*/
protected $authCode; protected $authCode;
/** /**
* @param \OAuth2\Storage\AuthorizationCodeInterface $storage REQUIRED Storage class for retrieving authorization code information * @param AuthorizationCodeInterface $storage - REQUIRED Storage class for retrieving authorization code information
*/ */
public function __construct(AuthorizationCodeInterface $storage) public function __construct(AuthorizationCodeInterface $storage)
{ {
$this->storage = $storage; $this->storage = $storage;
} }
public function getQuerystringIdentifier() /**
* @return string
*/
public function getQueryStringIdentifier()
{ {
return 'authorization_code'; return 'authorization_code';
} }
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
* @throws Exception
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response) public function validateRequest(RequestInterface $request, ResponseInterface $response)
{ {
if (!$request->request('code')) { if (!$request->request('code')) {
@ -75,21 +93,45 @@ class AuthorizationCode implements GrantTypeInterface
return true; return true;
} }
/**
* Get the client id
*
* @return mixed
*/
public function getClientId() public function getClientId()
{ {
return $this->authCode['client_id']; return $this->authCode['client_id'];
} }
/**
* Get the scope
*
* @return string
*/
public function getScope() public function getScope()
{ {
return isset($this->authCode['scope']) ? $this->authCode['scope'] : null; return isset($this->authCode['scope']) ? $this->authCode['scope'] : null;
} }
/**
* Get the user id
*
* @return mixed
*/
public function getUserId() public function getUserId()
{ {
return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null; return isset($this->authCode['user_id']) ? $this->authCode['user_id'] : null;
} }
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{ {
$token = $accessToken->createAccessToken($client_id, $user_id, $scope); $token = $accessToken->createAccessToken($client_id, $user_id, $scope);

View File

@ -9,12 +9,19 @@ use OAuth2\Storage\ClientCredentialsInterface;
/** /**
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
* *
* @see OAuth2\ClientAssertionType_HttpBasic * @see HttpBasic
*/ */
class ClientCredentials extends HttpBasic implements GrantTypeInterface class ClientCredentials extends HttpBasic implements GrantTypeInterface
{ {
/**
* @var array
*/
private $clientData; private $clientData;
/**
* @param ClientCredentialsInterface $storage
* @param array $config
*/
public function __construct(ClientCredentialsInterface $storage, array $config = array()) public function __construct(ClientCredentialsInterface $storage, array $config = array())
{ {
/** /**
@ -27,11 +34,21 @@ class ClientCredentials extends HttpBasic implements GrantTypeInterface
parent::__construct($storage, $config); parent::__construct($storage, $config);
} }
public function getQuerystringIdentifier() /**
* Get query string identifier
*
* @return string
*/
public function getQueryStringIdentifier()
{ {
return 'client_credentials'; return 'client_credentials';
} }
/**
* Get scope
*
* @return string|null
*/
public function getScope() public function getScope()
{ {
$this->loadClientData(); $this->loadClientData();
@ -39,6 +56,11 @@ class ClientCredentials extends HttpBasic implements GrantTypeInterface
return isset($this->clientData['scope']) ? $this->clientData['scope'] : null; return isset($this->clientData['scope']) ? $this->clientData['scope'] : null;
} }
/**
* Get user id
*
* @return mixed
*/
public function getUserId() public function getUserId()
{ {
$this->loadClientData(); $this->loadClientData();
@ -46,6 +68,15 @@ class ClientCredentials extends HttpBasic implements GrantTypeInterface
return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null; return isset($this->clientData['user_id']) ? $this->clientData['user_id'] : null;
} }
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{ {
/** /**

View File

@ -11,10 +11,49 @@ use OAuth2\ResponseInterface;
*/ */
interface GrantTypeInterface interface GrantTypeInterface
{ {
public function getQuerystringIdentifier(); /**
* Get query string identifier
*
* @return string
*/
public function getQueryStringIdentifier();
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return mixed
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response); public function validateRequest(RequestInterface $request, ResponseInterface $response);
/**
* Get client id
*
* @return mixed
*/
public function getClientId(); public function getClientId();
/**
* Get user id
*
* @return mixed
*/
public function getUserId(); public function getUserId();
/**
* Get scope
*
* @return string|null
*/
public function getScope(); public function getScope();
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope); public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope);
} }

View File

@ -30,10 +30,12 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/** /**
* Creates an instance of the JWT bearer grant type. * Creates an instance of the JWT bearer grant type.
* *
* @param OAuth2\Storage\JWTBearerInterface|JwtBearerInterface $storage A valid storage interface that implements storage hooks for the JWT bearer grant type. * @param JwtBearerInterface $storage - A valid storage interface that implements storage hooks for the JWT
* @param string $audience The audience to validate the token against. This is usually the full URI of the OAuth token requests endpoint. * bearer grant type.
* @param EncryptionInterface|OAuth2\Encryption\JWT $jwtUtil OPTONAL The class used to decode, encode and verify JWTs. * @param string $audience - The audience to validate the token against. This is usually the full
* @param array $config * URI of the OAuth token requests endpoint.
* @param EncryptionInterface|JWT $jwtUtil - OPTONAL The class used to decode, encode and verify JWTs.
* @param array $config
*/ */
public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array()) public function __construct(JwtBearerInterface $storage, $audience, EncryptionInterface $jwtUtil = null, array $config = array())
{ {
@ -56,12 +58,11 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/** /**
* Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant. * Returns the grant_type get parameter to identify the grant type request as JWT bearer authorization grant.
* *
* @return * @return string - The string identifier for grant_type.
* The string identifier for grant_type.
* *
* @see OAuth2\GrantType\GrantTypeInterface::getQuerystringIdentifier() * @see GrantTypeInterface::getQueryStringIdentifier()
*/ */
public function getQuerystringIdentifier() public function getQueryStringIdentifier()
{ {
return 'urn:ietf:params:oauth:grant-type:jwt-bearer'; return 'urn:ietf:params:oauth:grant-type:jwt-bearer';
} }
@ -69,10 +70,9 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
/** /**
* Validates the data from the decoded JWT. * Validates the data from the decoded JWT.
* *
* @return * @param RequestInterface $request
* TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned. * @param ResponseInterface $response
* * @return bool|mixed|null TRUE if the JWT request is valid and can be decoded. Otherwise, FALSE is returned.@see GrantTypeInterface::getTokenData()
* @see OAuth2\GrantType\GrantTypeInterface::getTokenData()
*/ */
public function validateRequest(RequestInterface $request, ResponseInterface $response) public function validateRequest(RequestInterface $request, ResponseInterface $response)
{ {
@ -196,16 +196,31 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
return true; return true;
} }
/**
* Get client id
*
* @return mixed
*/
public function getClientId() public function getClientId()
{ {
return $this->jwt['iss']; return $this->jwt['iss'];
} }
/**
* Get user id
*
* @return mixed
*/
public function getUserId() public function getUserId()
{ {
return $this->jwt['sub']; return $this->jwt['sub'];
} }
/**
* Get scope
*
* @return null
*/
public function getScope() public function getScope()
{ {
return null; return null;
@ -215,7 +230,13 @@ class JwtBearer implements GrantTypeInterface, ClientAssertionTypeInterface
* Creates an access token that is NOT associated with a refresh token. * Creates an access token that is NOT associated with a refresh token.
* If a subject (sub) the name of the user/account we are accessing data on behalf of. * If a subject (sub) the name of the user/account we are accessing data on behalf of.
* *
* @see OAuth2\GrantType\GrantTypeInterface::createAccessToken() * @see GrantTypeInterface::createAccessToken()
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/ */
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{ {

View File

@ -8,25 +8,34 @@ use OAuth2\RequestInterface;
use OAuth2\ResponseInterface; use OAuth2\ResponseInterface;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class RefreshToken implements GrantTypeInterface class RefreshToken implements GrantTypeInterface
{ {
/**
* @var array
*/
private $refreshToken; private $refreshToken;
/**
* @var RefreshTokenInterface
*/
protected $storage; protected $storage;
/**
* @var array
*/
protected $config; protected $config;
/** /**
* @param OAuth2\Storage\RefreshTokenInterface $storage REQUIRED Storage class for retrieving refresh token information * @param RefreshTokenInterface $storage - REQUIRED Storage class for retrieving refresh token information
* @param array $config OPTIONAL Configuration options for the server * @param array $config - OPTIONAL Configuration options for the server
* <code> * @code
* $config = array( * $config = array(
* 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request * 'always_issue_new_refresh_token' => true, // whether to issue a new refresh token upon successful token request
* 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using * 'unset_refresh_token_after_use' => true // whether to unset the refresh token after after using
* ); * );
* </code> * @endcode
*/ */
public function __construct(RefreshTokenInterface $storage, $config = array()) public function __construct(RefreshTokenInterface $storage, $config = array())
{ {
@ -45,11 +54,21 @@ class RefreshToken implements GrantTypeInterface
$this->storage = $storage; $this->storage = $storage;
} }
public function getQuerystringIdentifier() /**
* @return string
*/
public function getQueryStringIdentifier()
{ {
return 'refresh_token'; return 'refresh_token';
} }
/**
* Validate the OAuth request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed|null
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response) public function validateRequest(RequestInterface $request, ResponseInterface $response)
{ {
if (!$request->request("refresh_token")) { if (!$request->request("refresh_token")) {
@ -76,21 +95,45 @@ class RefreshToken implements GrantTypeInterface
return true; return true;
} }
/**
* Get client id
*
* @return mixed
*/
public function getClientId() public function getClientId()
{ {
return $this->refreshToken['client_id']; return $this->refreshToken['client_id'];
} }
/**
* Get user id
*
* @return mixed|null
*/
public function getUserId() public function getUserId()
{ {
return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null; return isset($this->refreshToken['user_id']) ? $this->refreshToken['user_id'] : null;
} }
/**
* Get scope
*
* @return null|string
*/
public function getScope() public function getScope()
{ {
return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null; return isset($this->refreshToken['scope']) ? $this->refreshToken['scope'] : null;
} }
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{ {
/* /*

View File

@ -6,30 +6,46 @@ use OAuth2\Storage\UserCredentialsInterface;
use OAuth2\ResponseType\AccessTokenInterface; use OAuth2\ResponseType\AccessTokenInterface;
use OAuth2\RequestInterface; use OAuth2\RequestInterface;
use OAuth2\ResponseInterface; use OAuth2\ResponseInterface;
use LogicException;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class UserCredentials implements GrantTypeInterface class UserCredentials implements GrantTypeInterface
{ {
/**
* @var array
*/
private $userInfo; private $userInfo;
/**
* @var UserCredentialsInterface
*/
protected $storage; protected $storage;
/** /**
* @param OAuth2\Storage\UserCredentialsInterface $storage REQUIRED Storage class for retrieving user credentials information * @param UserCredentialsInterface $storage - REQUIRED Storage class for retrieving user credentials information
*/ */
public function __construct(UserCredentialsInterface $storage) public function __construct(UserCredentialsInterface $storage)
{ {
$this->storage = $storage; $this->storage = $storage;
} }
public function getQuerystringIdentifier() /**
* @return string
*/
public function getQueryStringIdentifier()
{ {
return 'password'; return 'password';
} }
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool|mixed|null
*
* @throws LogicException
*/
public function validateRequest(RequestInterface $request, ResponseInterface $response) public function validateRequest(RequestInterface $request, ResponseInterface $response)
{ {
if (!$request->request("password") || !$request->request("username")) { if (!$request->request("password") || !$request->request("username")) {
@ -61,21 +77,45 @@ class UserCredentials implements GrantTypeInterface
return true; return true;
} }
/**
* Get client id
*
* @return mixed|null
*/
public function getClientId() public function getClientId()
{ {
return null; return null;
} }
/**
* Get user id
*
* @return mixed
*/
public function getUserId() public function getUserId()
{ {
return $this->userInfo['user_id']; return $this->userInfo['user_id'];
} }
/**
* Get scope
*
* @return null|string
*/
public function getScope() public function getScope()
{ {
return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null; return isset($this->userInfo['scope']) ? $this->userInfo['scope'] : null;
} }
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{ {
return $accessToken->createAccessToken($client_id, $user_id, $scope); return $accessToken->createAccessToken($client_id, $user_id, $scope);

View File

@ -11,8 +11,19 @@ use OAuth2\ResponseInterface;
*/ */
class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface class AuthorizeController extends BaseAuthorizeController implements AuthorizeControllerInterface
{ {
/**
* @var mixed
*/
private $nonce; private $nonce;
/**
* Set not authorized response
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param string $redirect_uri
* @param null $user_id
*/
protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null) protected function setNotAuthorizedResponse(RequestInterface $request, ResponseInterface $response, $redirect_uri, $user_id = null)
{ {
$prompt = $request->query('prompt', 'consent'); $prompt = $request->query('prompt', 'consent');
@ -32,6 +43,14 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
$response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message); $response->setRedirect($this->config['redirect_status_code'], $redirect_uri, $this->getState(), $error, $error_message);
} }
/**
* @TODO: add dependency injection for the parameters in this method
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @param mixed $user_id
* @return array
*/
protected function buildAuthorizeParameters($request, $response, $user_id) protected function buildAuthorizeParameters($request, $response, $user_id)
{ {
if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) { if (!$params = parent::buildAuthorizeParameters($request, $response, $user_id)) {
@ -49,6 +68,11 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
return $params; return $params;
} }
/**
* @param RequestInterface $request
* @param ResponseInterface $response
* @return bool
*/
public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response) public function validateAuthorizeRequest(RequestInterface $request, ResponseInterface $response)
{ {
if (!parent::validateAuthorizeRequest($request, $response)) { if (!parent::validateAuthorizeRequest($request, $response)) {
@ -69,6 +93,11 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
return true; return true;
} }
/**
* Array of valid response types
*
* @return array
*/
protected function getValidResponseTypes() protected function getValidResponseTypes()
{ {
return array( return array(
@ -87,11 +116,8 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
* method checks whether OpenID Connect is enabled in the server settings * method checks whether OpenID Connect is enabled in the server settings
* and whether the openid scope was requested. * and whether the openid scope was requested.
* *
* @param $request_scope * @param string $request_scope - A space-separated string of scopes.
* A space-separated string of scopes. * @return boolean - TRUE if an id token is needed, FALSE otherwise.
*
* @return
* TRUE if an id token is needed, FALSE otherwise.
*/ */
public function needsIdToken($request_scope) public function needsIdToken($request_scope)
{ {
@ -99,6 +125,9 @@ class AuthorizeController extends BaseAuthorizeController implements AuthorizeCo
return $this->scopeUtil->checkScope('openid', $request_scope); return $this->scopeUtil->checkScope('openid', $request_scope);
} }
/**
* @return mixed
*/
public function getNonce() public function getNonce()
{ {
return $this->nonce; return $this->nonce;

View File

@ -5,6 +5,8 @@ namespace OAuth2\OpenID\Controller;
interface AuthorizeControllerInterface interface AuthorizeControllerInterface
{ {
const RESPONSE_TYPE_ID_TOKEN = 'id_token'; const RESPONSE_TYPE_ID_TOKEN = 'id_token';
const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token'; const RESPONSE_TYPE_ID_TOKEN_TOKEN = 'id_token token';
const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token'; const RESPONSE_TYPE_CODE_ID_TOKEN = 'code id_token';
} }

View File

@ -16,30 +16,34 @@ use OAuth2\ResponseInterface;
*/ */
class UserInfoController extends ResourceController implements UserInfoControllerInterface class UserInfoController extends ResourceController implements UserInfoControllerInterface
{ {
private $token; /**
* @var UserClaimsInterface
protected $tokenType; */
protected $tokenStorage;
protected $userClaimsStorage; protected $userClaimsStorage;
protected $config;
protected $scopeUtil;
/**
* Constructor
*
* @param TokenTypeInterface $tokenType
* @param AccessTokenInterface $tokenStorage
* @param UserClaimsInterface $userClaimsStorage
* @param array $config
* @param ScopeInterface $scopeUtil
*/
public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null) public function __construct(TokenTypeInterface $tokenType, AccessTokenInterface $tokenStorage, UserClaimsInterface $userClaimsStorage, $config = array(), ScopeInterface $scopeUtil = null)
{ {
$this->tokenType = $tokenType; parent::__construct($tokenType, $tokenStorage, $config, $scopeUtil);
$this->tokenStorage = $tokenStorage;
$this->userClaimsStorage = $userClaimsStorage; $this->userClaimsStorage = $userClaimsStorage;
$this->config = array_merge(array(
'www_realm' => 'Service',
), $config);
if (is_null($scopeUtil)) {
$scopeUtil = new Scope();
}
$this->scopeUtil = $scopeUtil;
} }
/**
* Handle the user info request
*
* @param RequestInterface $request
* @param ResponseInterface $response
* @return void
*/
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response) public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response)
{ {
if (!$this->verifyResourceRequest($request, $response, 'openid')) { if (!$this->verifyResourceRequest($request, $response, 'openid')) {
@ -55,4 +59,4 @@ class UserInfoController extends ResourceController implements UserInfoControlle
); );
$response->addParameters($claims); $response->addParameters($claims);
} }
} }

View File

@ -9,15 +9,22 @@ use OAuth2\ResponseInterface;
* This controller is called when the user claims for OpenID Connect's * This controller is called when the user claims for OpenID Connect's
* UserInfo endpoint should be returned. * UserInfo endpoint should be returned.
* *
* ex: * @code
* > $response = new OAuth2\Response(); * $response = new OAuth2\Response();
* > $userInfoController->handleUserInfoRequest( * $userInfoController->handleUserInfoRequest(
* > OAuth2\Request::createFromGlobals(), * OAuth2\Request::createFromGlobals(),
* > $response; * $response
* > $response->send(); * );
* * $response->send();
* @endcode
*/ */
interface UserInfoControllerInterface interface UserInfoControllerInterface
{ {
/**
* Handle user info request
*
* @param RequestInterface $request
* @param ResponseInterface $response
*/
public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response); public function handleUserInfoRequest(RequestInterface $request, ResponseInterface $response);
} }

View File

@ -6,11 +6,19 @@ use OAuth2\GrantType\AuthorizationCode as BaseAuthorizationCode;
use OAuth2\ResponseType\AccessTokenInterface; use OAuth2\ResponseType\AccessTokenInterface;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class AuthorizationCode extends BaseAuthorizationCode class AuthorizationCode extends BaseAuthorizationCode
{ {
/**
* Create access token
*
* @param AccessTokenInterface $accessToken
* @param mixed $client_id - client identifier related to the access token.
* @param mixed $user_id - user id associated with the access token
* @param string $scope - scopes to be stored in space-separated string.
* @return array
*/
public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope) public function createAccessToken(AccessTokenInterface $accessToken, $client_id, $user_id, $scope)
{ {
$includeRefreshToken = true; $includeRefreshToken = true;

View File

@ -6,16 +6,26 @@ use OAuth2\ResponseType\AuthorizationCode as BaseAuthorizationCode;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface; use OAuth2\OpenID\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCodeInterface
{ {
/**
* Constructor
*
* @param AuthorizationCodeStorageInterface $storage
* @param array $config
*/
public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array()) public function __construct(AuthorizationCodeStorageInterface $storage, array $config = array())
{ {
parent::__construct($storage, $config); parent::__construct($storage, $config);
} }
/**
* @param $params
* @param null $user_id
* @return array
*/
public function getAuthorizeResponse($params, $user_id = null) public function getAuthorizeResponse($params, $user_id = null)
{ {
// build the URL to redirect to // build the URL to redirect to
@ -35,18 +45,14 @@ class AuthorizationCode extends BaseAuthorizationCode implements AuthorizationCo
/** /**
* Handle the creation of the authorization code. * Handle the creation of the authorization code.
* *
* @param $client_id * @param mixed $client_id - Client identifier related to the authorization code
* Client identifier related to the authorization code * @param mixed $user_id - User ID associated with the authorization code
* @param $user_id * @param string $redirect_uri - An absolute URI to which the authorization server will redirect the
* User ID associated with the authorization code * user-agent to when the end-user authorization step is completed.
* @param $redirect_uri * @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* An absolute URI to which the authorization server will redirect the * @param string $id_token - OPTIONAL The OpenID Connect id_token.
* user-agent to when the end-user authorization step is completed.
* @param $scope
* (optional) Scopes to be stored in space-separated string.
* @param $id_token
* (optional) The OpenID Connect id_token.
* *
* @return string
* @see http://tools.ietf.org/html/rfc6749#section-4 * @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
*/ */

View File

@ -5,7 +5,6 @@ namespace OAuth2\OpenID\ResponseType;
use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface; use OAuth2\ResponseType\AuthorizationCodeInterface as BaseAuthorizationCodeInterface;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
@ -13,12 +12,13 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
/** /**
* Handle the creation of the authorization code. * Handle the creation of the authorization code.
* *
* @param $client_id Client identifier related to the authorization code * @param mixed $client_id - Client identifier related to the authorization code
* @param $user_id User ID associated with the authorization code * @param mixed $user_id - User ID associated with the authorization code
* @param $redirect_uri An absolute URI to which the authorization server will redirect the * @param string $redirect_uri - An absolute URI to which the authorization server will redirect the
* user-agent to when the end-user authorization step is completed. * user-agent to when the end-user authorization step is completed.
* @param $scope OPTIONAL Scopes to be stored in space-separated string. * @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* @param $id_token OPTIONAL The OpenID Connect id_token. * @param string $id_token - OPTIONAL The OpenID Connect id_token.
* @return string
* *
* @see http://tools.ietf.org/html/rfc6749#section-4 * @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4

View File

@ -4,15 +4,31 @@ namespace OAuth2\OpenID\ResponseType;
class CodeIdToken implements CodeIdTokenInterface class CodeIdToken implements CodeIdTokenInterface
{ {
/**
* @var AuthorizationCodeInterface
*/
protected $authCode; protected $authCode;
/**
* @var IdTokenInterface
*/
protected $idToken; protected $idToken;
/**
* @param AuthorizationCodeInterface $authCode
* @param IdTokenInterface $idToken
*/
public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken) public function __construct(AuthorizationCodeInterface $authCode, IdTokenInterface $idToken)
{ {
$this->authCode = $authCode; $this->authCode = $authCode;
$this->idToken = $idToken; $this->idToken = $idToken;
} }
/**
* @param array $params
* @param mixed $user_id
* @return mixed
*/
public function getAuthorizeResponse($params, $user_id = null) public function getAuthorizeResponse($params, $user_id = null)
{ {
$result = $this->authCode->getAuthorizeResponse($params, $user_id); $result = $this->authCode->getAuthorizeResponse($params, $user_id);

View File

@ -6,14 +6,38 @@ use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt; use OAuth2\Encryption\Jwt;
use OAuth2\Storage\PublicKeyInterface; use OAuth2\Storage\PublicKeyInterface;
use OAuth2\OpenID\Storage\UserClaimsInterface; use OAuth2\OpenID\Storage\UserClaimsInterface;
use LogicException;
class IdToken implements IdTokenInterface class IdToken implements IdTokenInterface
{ {
/**
* @var UserClaimsInterface
*/
protected $userClaimsStorage; protected $userClaimsStorage;
/**
* @var PublicKeyInterface
*/
protected $publicKeyStorage; protected $publicKeyStorage;
/**
* @var array
*/
protected $config; protected $config;
/**
* @var EncryptionInterface
*/
protected $encryptionUtil; protected $encryptionUtil;
/**
* Constructor
*
* @param UserClaimsInterface $userClaimsStorage
* @param PublicKeyInterface $publicKeyStorage
* @param array $config
* @param EncryptionInterface $encryptionUtil
* @throws LogicException
*/
public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null) public function __construct(UserClaimsInterface $userClaimsStorage, PublicKeyInterface $publicKeyStorage, array $config = array(), EncryptionInterface $encryptionUtil = null)
{ {
$this->userClaimsStorage = $userClaimsStorage; $this->userClaimsStorage = $userClaimsStorage;
@ -24,13 +48,18 @@ class IdToken implements IdTokenInterface
$this->encryptionUtil = $encryptionUtil; $this->encryptionUtil = $encryptionUtil;
if (!isset($config['issuer'])) { if (!isset($config['issuer'])) {
throw new \LogicException('config parameter "issuer" must be set'); throw new LogicException('config parameter "issuer" must be set');
} }
$this->config = array_merge(array( $this->config = array_merge(array(
'id_lifetime' => 3600, 'id_lifetime' => 3600,
), $config); ), $config);
} }
/**
* @param array $params
* @param null $userInfo
* @return array|mixed
*/
public function getAuthorizeResponse($params, $userInfo = null) public function getAuthorizeResponse($params, $userInfo = null)
{ {
// build the URL to redirect to // build the URL to redirect to
@ -50,6 +79,16 @@ class IdToken implements IdTokenInterface
return array($params['redirect_uri'], $result); return array($params['redirect_uri'], $result);
} }
/**
* Create id token
*
* @param string $client_id
* @param mixed $userInfo
* @param mixed $nonce
* @param mixed $userClaims
* @param mixed $access_token
* @return mixed|string
*/
public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null) public function createIdToken($client_id, $userInfo, $nonce = null, $userClaims = null, $access_token = null)
{ {
// pull auth_time from user info if supplied // pull auth_time from user info if supplied
@ -79,6 +118,11 @@ class IdToken implements IdTokenInterface
return $this->encodeToken($token, $client_id); return $this->encodeToken($token, $client_id);
} }
/**
* @param $access_token
* @param null $client_id
* @return mixed|string
*/
protected function createAtHash($access_token, $client_id = null) protected function createAtHash($access_token, $client_id = null)
{ {
// maps HS256 and RS256 to sha256, etc. // maps HS256 and RS256 to sha256, etc.
@ -90,6 +134,11 @@ class IdToken implements IdTokenInterface
return $this->encryptionUtil->urlSafeB64Encode($at_hash); return $this->encryptionUtil->urlSafeB64Encode($at_hash);
} }
/**
* @param array $token
* @param null $client_id
* @return mixed|string
*/
protected function encodeToken(array $token, $client_id = null) protected function encodeToken(array $token, $client_id = null)
{ {
$private_key = $this->publicKeyStorage->getPrivateKey($client_id); $private_key = $this->publicKeyStorage->getPrivateKey($client_id);
@ -98,6 +147,11 @@ class IdToken implements IdTokenInterface
return $this->encryptionUtil->encode($token, $private_key, $algorithm); return $this->encryptionUtil->encode($token, $private_key, $algorithm);
} }
/**
* @param $userInfo
* @return array
* @throws LogicException
*/
private function getUserIdAndAuthTime($userInfo) private function getUserIdAndAuthTime($userInfo)
{ {
$auth_time = null; $auth_time = null;
@ -105,7 +159,7 @@ class IdToken implements IdTokenInterface
// support an array for user_id / auth_time // support an array for user_id / auth_time
if (is_array($userInfo)) { if (is_array($userInfo)) {
if (!isset($userInfo['user_id'])) { if (!isset($userInfo['user_id'])) {
throw new \LogicException('if $user_id argument is an array, user_id index must be set'); throw new LogicException('if $user_id argument is an array, user_id index must be set');
} }
$auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null; $auth_time = isset($userInfo['auth_time']) ? $userInfo['auth_time'] : null;

View File

@ -15,12 +15,13 @@ interface IdTokenInterface extends ResponseTypeInterface
* If the Implicit Flow is used, the token and id_token are generated and * If the Implicit Flow is used, the token and id_token are generated and
* returned together. * returned together.
* *
* @param string $client_id The client id. * @param string $client_id - The client id.
* @param string $user_id The user id. * @param mixed $userInfo - User info
* @param string $nonce OPTIONAL The nonce. * @param string $nonce - OPTIONAL The nonce.
* @param string $userClaims OPTIONAL Claims about the user. * @param string $userClaims - OPTIONAL Claims about the user.
* @param string $access_token OPTIONAL The access token, if known. * @param string $access_token - OPTIONAL The access token, if known.
*
* @internal param string $user_id - The user id.
* @return string The ID Token represented as a JSON Web Token (JWT). * @return string The ID Token represented as a JSON Web Token (JWT).
* *
* @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken * @see http://openid.net/specs/openid-connect-core-1_0.html#IDToken

View File

@ -6,15 +6,33 @@ use OAuth2\ResponseType\AccessTokenInterface;
class IdTokenToken implements IdTokenTokenInterface class IdTokenToken implements IdTokenTokenInterface
{ {
/**
* @var AccessTokenInterface
*/
protected $accessToken; protected $accessToken;
/**
* @var IdTokenInterface
*/
protected $idToken; protected $idToken;
/**
* Constructor
*
* @param AccessTokenInterface $accessToken
* @param IdTokenInterface $idToken
*/
public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken) public function __construct(AccessTokenInterface $accessToken, IdTokenInterface $idToken)
{ {
$this->accessToken = $accessToken; $this->accessToken = $accessToken;
$this->idToken = $idToken; $this->idToken = $idToken;
} }
/**
* @param array $params
* @param mixed $user_id
* @return mixed
*/
public function getAuthorizeResponse($params, $user_id = null) public function getAuthorizeResponse($params, $user_id = null)
{ {
$result = $this->accessToken->getAuthorizeResponse($params, $user_id); $result = $this->accessToken->getAuthorizeResponse($params, $user_id);

View File

@ -23,13 +23,13 @@ interface AuthorizationCodeInterface extends BaseAuthorizationCodeInterface
* *
* Required for OAuth2::GRANT_TYPE_AUTH_CODE. * Required for OAuth2::GRANT_TYPE_AUTH_CODE.
* *
* @param $code authorization code to be stored. * @param string $code - authorization code to be stored.
* @param $client_id client identifier to be stored. * @param mixed $client_id - client identifier to be stored.
* @param $user_id user identifier to be stored. * @param mixed $user_id - user identifier to be stored.
* @param string $redirect_uri redirect URI(s) to be stored in a space-separated string. * @param string $redirect_uri - redirect URI(s) to be stored in a space-separated string.
* @param int $expires expiration to be stored as a Unix timestamp. * @param int $expires - expiration to be stored as a Unix timestamp.
* @param string $scope OPTIONAL scopes to be stored in space-separated string. * @param string $scope - OPTIONAL scopes to be stored in space-separated string.
* @param string $id_token OPTIONAL the OpenID Connect id_token. * @param string $id_token - OPTIONAL the OpenID Connect id_token.
* *
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
*/ */

View File

@ -23,14 +23,11 @@ interface UserClaimsInterface
* Groups of claims are returned based on the requested scopes. No group * Groups of claims are returned based on the requested scopes. No group
* is required, and no claim is required. * is required, and no claim is required.
* *
* @param $user_id * @param mixed $user_id - The id of the user for which claims should be returned.
* The id of the user for which claims should be returned. * @param string $scope - The requested scope.
* @param $scope
* The requested scope.
* Scopes with matching claims: profile, email, address, phone. * Scopes with matching claims: profile, email, address, phone.
* *
* @return * @return array - An array in the claim => value format.
* An array in the claim => value format.
* *
* @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims * @see http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
*/ */

View File

@ -2,6 +2,8 @@
namespace OAuth2; namespace OAuth2;
use LogicException;
/** /**
* OAuth2\Request * OAuth2\Request
* This class is taken from the Symfony2 Framework and is part of the Symfony package. * This class is taken from the Symfony2 Framework and is part of the Symfony package.
@ -21,13 +23,14 @@ class Request implements RequestInterface
/** /**
* Constructor. * Constructor.
* *
* @param array $query The GET parameters * @param array $query - The GET parameters
* @param array $request The POST parameters * @param array $request - The POST parameters
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) * @param array $attributes - The request attributes (parameters parsed from the PATH_INFO, ...)
* @param array $cookies The COOKIE parameters * @param array $cookies - The COOKIE parameters
* @param array $files The FILES parameters * @param array $files - The FILES parameters
* @param array $server The SERVER parameters * @param array $server - The SERVER parameters
* @param string $content The raw body data * @param string $content - The raw body data
* @param array $headers - The headers
* *
* @api * @api
*/ */
@ -41,13 +44,14 @@ class Request implements RequestInterface
* *
* This method also re-initializes all properties. * This method also re-initializes all properties.
* *
* @param array $query The GET parameters * @param array $query - The GET parameters
* @param array $request The POST parameters * @param array $request - The POST parameters
* @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) * @param array $attributes - The request attributes (parameters parsed from the PATH_INFO, ...)
* @param array $cookies The COOKIE parameters * @param array $cookies - The COOKIE parameters
* @param array $files The FILES parameters * @param array $files - The FILES parameters
* @param array $server The SERVER parameters * @param array $server - The SERVER parameters
* @param string $content The raw body data * @param string $content - The raw body data
* @param array $headers - The headers
* *
* @api * @api
*/ */
@ -63,21 +67,41 @@ class Request implements RequestInterface
$this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers; $this->headers = is_null($headers) ? $this->getHeadersFromServer($this->server) : $headers;
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function query($name, $default = null) public function query($name, $default = null)
{ {
return isset($this->query[$name]) ? $this->query[$name] : $default; return isset($this->query[$name]) ? $this->query[$name] : $default;
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function request($name, $default = null) public function request($name, $default = null)
{ {
return isset($this->request[$name]) ? $this->request[$name] : $default; return isset($this->request[$name]) ? $this->request[$name] : $default;
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function server($name, $default = null) public function server($name, $default = null)
{ {
return isset($this->server[$name]) ? $this->server[$name] : $default; return isset($this->server[$name]) ? $this->server[$name] : $default;
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function headers($name, $default = null) public function headers($name, $default = null)
{ {
$headers = array_change_key_case($this->headers); $headers = array_change_key_case($this->headers);
@ -86,6 +110,9 @@ class Request implements RequestInterface
return isset($headers[$name]) ? $headers[$name] : $default; return isset($headers[$name]) ? $headers[$name] : $default;
} }
/**
* @return array
*/
public function getAllQueryParameters() public function getAllQueryParameters()
{ {
return $this->query; return $this->query;
@ -94,14 +121,15 @@ class Request implements RequestInterface
/** /**
* Returns the request body content. * Returns the request body content.
* *
* @param Boolean $asResource If true, a resource will be returned * @param boolean $asResource - If true, a resource will be returned
* @return string|resource - The request body content or a resource to read the body stream.
* *
* @return string|resource The request body content or a resource to read the body stream. * @throws LogicException
*/ */
public function getContent($asResource = false) public function getContent($asResource = false)
{ {
if (false === $this->content || (true === $asResource && null !== $this->content)) { if (false === $this->content || (true === $asResource && null !== $this->content)) {
throw new \LogicException('getContent() can only be called once when using the resource return type.'); throw new LogicException('getContent() can only be called once when using the resource return type.');
} }
if (true === $asResource) { if (true === $asResource) {
@ -117,6 +145,10 @@ class Request implements RequestInterface
return $this->content; return $this->content;
} }
/**
* @param array $server
* @return array
*/
private function getHeadersFromServer($server) private function getHeadersFromServer($server)
{ {
$headers = array(); $headers = array();
@ -185,13 +217,15 @@ class Request implements RequestInterface
/** /**
* Creates a new request with values from PHP's super globals. * Creates a new request with values from PHP's super globals.
* *
* @return Request A new request * @return Request - A new request
* *
* @api * @api
*/ */
public static function createFromGlobals() public static function createFromGlobals()
{ {
$class = get_called_class(); $class = get_called_class();
/** @var Request $request */
$request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER); $request = new $class($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
$contentType = $request->server('CONTENT_TYPE', ''); $contentType = $request->server('CONTENT_TYPE', '');

View File

@ -4,13 +4,36 @@ namespace OAuth2;
interface RequestInterface interface RequestInterface
{ {
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function query($name, $default = null); public function query($name, $default = null);
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function request($name, $default = null); public function request($name, $default = null);
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function server($name, $default = null); public function server($name, $default = null);
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function headers($name, $default = null); public function headers($name, $default = null);
/**
* @return mixed
*/
public function getAllQueryParameters(); public function getAllQueryParameters();
} }

View File

@ -2,6 +2,8 @@
namespace OAuth2; namespace OAuth2;
use InvalidArgumentException;
/** /**
* Class to handle OAuth2 Responses in a graceful way. Use this interface * Class to handle OAuth2 Responses in a graceful way. Use this interface
* to output the proper OAuth2 responses. * to output the proper OAuth2 responses.
@ -13,12 +15,34 @@ namespace OAuth2;
*/ */
class Response implements ResponseInterface class Response implements ResponseInterface
{ {
/**
* @var string
*/
public $version; public $version;
/**
* @var int
*/
protected $statusCode = 200; protected $statusCode = 200;
/**
* @var string
*/
protected $statusText; protected $statusText;
/**
* @var array
*/
protected $parameters = array(); protected $parameters = array();
/**
* @var array
*/
protected $httpHeaders = array(); protected $httpHeaders = array();
/**
* @var array
*/
public static $statusTexts = array( public static $statusTexts = array(
100 => 'Continue', 100 => 'Continue',
101 => 'Switching Protocols', 101 => 'Switching Protocols',
@ -63,6 +87,11 @@ class Response implements ResponseInterface
505 => 'HTTP Version Not Supported', 505 => 'HTTP Version Not Supported',
); );
/**
* @param array $parameters
* @param int $statusCode
* @param array $headers
*/
public function __construct($parameters = array(), $statusCode = 200, $headers = array()) public function __construct($parameters = array(), $statusCode = 200, $headers = array())
{ {
$this->setParameters($parameters); $this->setParameters($parameters);
@ -102,76 +131,128 @@ class Response implements ResponseInterface
return sprintf("%s: %s\n", $name, $value); return sprintf("%s: %s\n", $name, $value);
} }
/**
* @return int
*/
public function getStatusCode() public function getStatusCode()
{ {
return $this->statusCode; return $this->statusCode;
} }
/**
* @param int $statusCode
* @param string $text
* @throws InvalidArgumentException
*/
public function setStatusCode($statusCode, $text = null) public function setStatusCode($statusCode, $text = null)
{ {
$this->statusCode = (int) $statusCode; $this->statusCode = (int) $statusCode;
if ($this->isInvalid()) { if ($this->isInvalid()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode)); throw new InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $statusCode));
} }
$this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text); $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text);
} }
/**
* @return string
*/
public function getStatusText() public function getStatusText()
{ {
return $this->statusText; return $this->statusText;
} }
/**
* @return array
*/
public function getParameters() public function getParameters()
{ {
return $this->parameters; return $this->parameters;
} }
/**
* @param array $parameters
*/
public function setParameters(array $parameters) public function setParameters(array $parameters)
{ {
$this->parameters = $parameters; $this->parameters = $parameters;
} }
/**
* @param array $parameters
*/
public function addParameters(array $parameters) public function addParameters(array $parameters)
{ {
$this->parameters = array_merge($this->parameters, $parameters); $this->parameters = array_merge($this->parameters, $parameters);
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getParameter($name, $default = null) public function getParameter($name, $default = null)
{ {
return isset($this->parameters[$name]) ? $this->parameters[$name] : $default; return isset($this->parameters[$name]) ? $this->parameters[$name] : $default;
} }
/**
* @param string $name
* @param mixed $value
*/
public function setParameter($name, $value) public function setParameter($name, $value)
{ {
$this->parameters[$name] = $value; $this->parameters[$name] = $value;
} }
/**
* @param array $httpHeaders
*/
public function setHttpHeaders(array $httpHeaders) public function setHttpHeaders(array $httpHeaders)
{ {
$this->httpHeaders = $httpHeaders; $this->httpHeaders = $httpHeaders;
} }
/**
* @param string $name
* @param mixed $value
*/
public function setHttpHeader($name, $value) public function setHttpHeader($name, $value)
{ {
$this->httpHeaders[$name] = $value; $this->httpHeaders[$name] = $value;
} }
/**
* @param array $httpHeaders
*/
public function addHttpHeaders(array $httpHeaders) public function addHttpHeaders(array $httpHeaders)
{ {
$this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders); $this->httpHeaders = array_merge($this->httpHeaders, $httpHeaders);
} }
/**
* @return array
*/
public function getHttpHeaders() public function getHttpHeaders()
{ {
return $this->httpHeaders; return $this->httpHeaders;
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getHttpHeader($name, $default = null) public function getHttpHeader($name, $default = null)
{ {
return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default; return isset($this->httpHeaders[$name]) ? $this->httpHeaders[$name] : $default;
} }
/**
* @param string $format
* @return mixed
* @throws InvalidArgumentException
*/
public function getResponseBody($format = 'json') public function getResponseBody($format = 'json')
{ {
switch ($format) { switch ($format) {
@ -187,10 +268,13 @@ class Response implements ResponseInterface
return $xml->asXML(); return $xml->asXML();
} }
throw new \InvalidArgumentException(sprintf('The format %s is not supported', $format)); throw new InvalidArgumentException(sprintf('The format %s is not supported', $format));
} }
/**
* @param string $format
*/
public function send($format = 'json') public function send($format = 'json')
{ {
// headers have already been sent by the developer // headers have already been sent by the developer
@ -215,6 +299,14 @@ class Response implements ResponseInterface
echo $this->getResponseBody($format); echo $this->getResponseBody($format);
} }
/**
* @param int $statusCode
* @param string $error
* @param string $errorDescription
* @param string $errorUri
* @return mixed
* @throws InvalidArgumentException
*/
public function setError($statusCode, $error, $errorDescription = null, $errorUri = null) public function setError($statusCode, $error, $errorDescription = null, $errorUri = null)
{ {
$parameters = array( $parameters = array(
@ -239,14 +331,24 @@ class Response implements ResponseInterface
$this->addHttpHeaders($httpHeaders); $this->addHttpHeaders($httpHeaders);
if (!$this->isClientError() && !$this->isServerError()) { if (!$this->isClientError() && !$this->isServerError()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode)); throw new InvalidArgumentException(sprintf('The HTTP status code is not an error ("%s" given).', $statusCode));
} }
} }
/**
* @param int $statusCode
* @param string $url
* @param string $state
* @param string $error
* @param string $errorDescription
* @param string $errorUri
* @return mixed
* @throws InvalidArgumentException
*/
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null) public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null)
{ {
if (empty($url)) { if (empty($url)) {
throw new \InvalidArgumentException('Cannot redirect to an empty URL.'); throw new InvalidArgumentException('Cannot redirect to an empty URL.');
} }
$parameters = array(); $parameters = array();
@ -271,15 +373,16 @@ class Response implements ResponseInterface
$this->addHttpHeaders(array('Location' => $url)); $this->addHttpHeaders(array('Location' => $url));
if (!$this->isRedirection()) { if (!$this->isRedirection()) {
throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode)); throw new InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $statusCode));
} }
} }
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
/** /**
* @return Boolean * @return Boolean
* *
* @api * @api
*
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
*/ */
public function isInvalid() public function isInvalid()
{ {
@ -336,8 +439,11 @@ class Response implements ResponseInterface
return $this->statusCode >= 500 && $this->statusCode < 600; return $this->statusCode >= 500 && $this->statusCode < 600;
} }
/* /**
* Functions from Symfony2 HttpFoundation - output pretty header * Function from Symfony2 HttpFoundation - output pretty header
*
* @param array $headers
* @return string
*/ */
private function getHttpHeadersAsString($headers) private function getHttpHeadersAsString($headers)
{ {
@ -357,11 +463,23 @@ class Response implements ResponseInterface
return $content; return $content;
} }
/**
* Function from Symfony2 HttpFoundation - output pretty header
*
* @param string $name
* @return mixed
*/
private function beautifyHeaderName($name) private function beautifyHeaderName($name)
{ {
return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name)); return preg_replace_callback('/\-(.)/', array($this, 'beautifyCallback'), ucfirst($name));
} }
/**
* Function from Symfony2 HttpFoundation - output pretty header
*
* @param array $match
* @return string
*/
private function beautifyCallback($match) private function beautifyCallback($match)
{ {
return '-'.strtoupper($match[1]); return '-'.strtoupper($match[1]);

View File

@ -6,19 +6,48 @@ namespace OAuth2;
* Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses * Interface which represents an object response. Meant to handle and display the proper OAuth2 Responses
* for errors and successes * for errors and successes
* *
* @see OAuth2\Response * @see \OAuth2\Response
*/ */
interface ResponseInterface interface ResponseInterface
{ {
/**
* @param array $parameters
*/
public function addParameters(array $parameters); public function addParameters(array $parameters);
/**
* @param array $httpHeaders
*/
public function addHttpHeaders(array $httpHeaders); public function addHttpHeaders(array $httpHeaders);
/**
* @param int $statusCode
*/
public function setStatusCode($statusCode); public function setStatusCode($statusCode);
/**
* @param int $statusCode
* @param string $name
* @param string $description
* @param string $uri
* @return mixed
*/
public function setError($statusCode, $name, $description = null, $uri = null); public function setError($statusCode, $name, $description = null, $uri = null);
/**
* @param int $statusCode
* @param string $url
* @param string $state
* @param string $error
* @param string $errorDescription
* @param string $errorUri
* @return mixed
*/
public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null); public function setRedirect($statusCode, $url, $state = null, $error = null, $errorDescription = null, $errorUri = null);
/**
* @param string $name
* @return mixed
*/
public function getParameter($name); public function getParameter($name);
} }

View File

@ -4,28 +4,39 @@ namespace OAuth2\ResponseType;
use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface; use OAuth2\Storage\AccessTokenInterface as AccessTokenStorageInterface;
use OAuth2\Storage\RefreshTokenInterface; use OAuth2\Storage\RefreshTokenInterface;
use RuntimeException;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class AccessToken implements AccessTokenInterface class AccessToken implements AccessTokenInterface
{ {
/**
* @var AccessTokenInterface
*/
protected $tokenStorage; protected $tokenStorage;
/**
* @var RefreshTokenInterface
*/
protected $refreshStorage; protected $refreshStorage;
/**
* @var array
*/
protected $config; protected $config;
/** /**
* @param OAuth2\Storage\AccessTokenInterface $tokenStorage REQUIRED Storage class for saving access token information * @param AccessTokenStorageInterface $tokenStorage - REQUIRED Storage class for saving access token information
* @param OAuth2\Storage\RefreshTokenInterface $refreshStorage OPTIONAL Storage class for saving refresh token information * @param RefreshTokenInterface $refreshStorage - OPTIONAL Storage class for saving refresh token information
* @param array $config OPTIONAL Configuration options for the server * @param array $config - OPTIONAL Configuration options for the server
* <code> * @code
* $config = array( * $config = array(
* 'token_type' => 'bearer', // token type identifier * 'token_type' => 'bearer', // token type identifier
* 'access_lifetime' => 3600, // time before access token expires * 'access_lifetime' => 3600, // time before access token expires
* 'refresh_token_lifetime' => 1209600, // time before refresh token expires * 'refresh_token_lifetime' => 1209600, // time before refresh token expires
* ); * );
* </endcode> * @endcode
*/ */
public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array()) public function __construct(AccessTokenStorageInterface $tokenStorage, RefreshTokenInterface $refreshStorage = null, array $config = array())
{ {
@ -39,6 +50,13 @@ class AccessToken implements AccessTokenInterface
), $config); ), $config);
} }
/**
* Get authorize response
*
* @param array $params
* @param mixed $user_id
* @return array
*/
public function getAuthorizeResponse($params, $user_id = null) public function getAuthorizeResponse($params, $user_id = null)
{ {
// build the URL to redirect to // build the URL to redirect to
@ -64,10 +82,11 @@ class AccessToken implements AccessTokenInterface
/** /**
* Handle the creation of access token, also issue refresh token if supported / desirable. * Handle the creation of access token, also issue refresh token if supported / desirable.
* *
* @param $client_id client identifier related to the access token. * @param mixed $client_id - client identifier related to the access token.
* @param $user_id user ID associated with the access token * @param mixed $user_id - user ID associated with the access token
* @param $scope OPTIONAL scopes to be stored in space-separated string. * @param string $scope - OPTIONAL scopes to be stored in space-separated string.
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response * @param bool $includeRefreshToken - if true, a new refresh_token will be added to the response
* @return array
* *
* @see http://tools.ietf.org/html/rfc6749#section-5 * @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5 * @ingroup oauth2_section_5
@ -107,13 +126,18 @@ class AccessToken implements AccessTokenInterface
* Implementing classes may want to override this function to implement * Implementing classes may want to override this function to implement
* other access token generation schemes. * other access token generation schemes.
* *
* @return * @return string - A unique access token.
* An unique access token.
* *
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
*/ */
protected function generateAccessToken() protected function generateAccessToken()
{ {
if (function_exists('random_bytes')) {
$randomData = random_bytes(20);
if ($randomData !== false && strlen($randomData) === 20) {
return bin2hex($randomData);
}
}
if (function_exists('openssl_random_pseudo_bytes')) { if (function_exists('openssl_random_pseudo_bytes')) {
$randomData = openssl_random_pseudo_bytes(20); $randomData = openssl_random_pseudo_bytes(20);
if ($randomData !== false && strlen($randomData) === 20) { if ($randomData !== false && strlen($randomData) === 20) {
@ -144,8 +168,7 @@ class AccessToken implements AccessTokenInterface
* Implementing classes may want to override this function to implement * Implementing classes may want to override this function to implement
* other refresh token generation schemes. * other refresh token generation schemes.
* *
* @return * @return string - A unique refresh token.
* An unique refresh.
* *
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
* @see OAuth2::generateAccessToken() * @see OAuth2::generateAccessToken()
@ -162,6 +185,7 @@ class AccessToken implements AccessTokenInterface
* *
* @param $token * @param $token
* @param null $tokenTypeHint * @param null $tokenTypeHint
* @throws RuntimeException
* @return boolean * @return boolean
*/ */
public function revokeToken($token, $tokenTypeHint = null) public function revokeToken($token, $tokenTypeHint = null)
@ -174,7 +198,7 @@ class AccessToken implements AccessTokenInterface
/** @TODO remove in v2 */ /** @TODO remove in v2 */
if (!method_exists($this->tokenStorage, 'unsetAccessToken')) { if (!method_exists($this->tokenStorage, 'unsetAccessToken')) {
throw new \RuntimeException( throw new RuntimeException(
sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage) sprintf('Token storage %s must implement unsetAccessToken method', get_class($this->tokenStorage)
)); ));
} }

View File

@ -3,7 +3,6 @@
namespace OAuth2\ResponseType; namespace OAuth2\ResponseType;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
interface AccessTokenInterface extends ResponseTypeInterface interface AccessTokenInterface extends ResponseTypeInterface
@ -11,10 +10,10 @@ interface AccessTokenInterface extends ResponseTypeInterface
/** /**
* Handle the creation of access token, also issue refresh token if supported / desirable. * Handle the creation of access token, also issue refresh token if supported / desirable.
* *
* @param $client_id client identifier related to the access token. * @param mixed $client_id - client identifier related to the access token.
* @param $user_id user ID associated with the access token * @param mixed $user_id - user ID associated with the access token
* @param $scope OPTONAL scopes to be stored in space-separated string. * @param string $scope - OPTONAL scopes to be stored in space-separated string.
* @param bool $includeRefreshToken if true, a new refresh_token will be added to the response * @param bool $includeRefreshToken - if true, a new refresh_token will be added to the response
* *
* @see http://tools.ietf.org/html/rfc6749#section-5 * @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5 * @ingroup oauth2_section_5
@ -31,4 +30,4 @@ interface AccessTokenInterface extends ResponseTypeInterface
* @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
*/ */
//public function revokeToken($token, $tokenTypeHint); //public function revokeToken($token, $tokenTypeHint);
} }

View File

@ -5,7 +5,6 @@ namespace OAuth2\ResponseType;
use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface; use OAuth2\Storage\AuthorizationCodeInterface as AuthorizationCodeStorageInterface;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class AuthorizationCode implements AuthorizationCodeInterface class AuthorizationCode implements AuthorizationCodeInterface
@ -85,7 +84,9 @@ class AuthorizationCode implements AuthorizationCodeInterface
protected function generateAuthorizationCode() protected function generateAuthorizationCode()
{ {
$tokenLen = 40; $tokenLen = 40;
if (function_exists('openssl_random_pseudo_bytes')) { if (function_exists('random_bytes')) {
$randomData = random_bytes(100);
} elseif (function_exists('openssl_random_pseudo_bytes')) {
$randomData = openssl_random_pseudo_bytes(100); $randomData = openssl_random_pseudo_bytes(100);
} elseif (function_exists('mcrypt_create_iv')) { } elseif (function_exists('mcrypt_create_iv')) {
$randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM); $randomData = mcrypt_create_iv(100, MCRYPT_DEV_URANDOM);

View File

@ -3,7 +3,6 @@
namespace OAuth2\ResponseType; namespace OAuth2\ResponseType;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
interface AuthorizationCodeInterface extends ResponseTypeInterface interface AuthorizationCodeInterface extends ResponseTypeInterface
@ -17,11 +16,12 @@ interface AuthorizationCodeInterface extends ResponseTypeInterface
/** /**
* Handle the creation of the authorization code. * Handle the creation of the authorization code.
* *
* @param $client_id client identifier related to the authorization code * @param mixed $client_id - Client identifier related to the authorization code
* @param $user_id user id associated with the authorization code * @param mixed $user_id - User ID associated with the authorization code
* @param $redirect_uri an absolute URI to which the authorization server will redirect the * @param string $redirect_uri - An absolute URI to which the authorization server will redirect the
* user-agent to when the end-user authorization step is completed. * user-agent to when the end-user authorization step is completed.
* @param $scope OPTIONAL scopes to be stored in space-separated string. * @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* @return string
* *
* @see http://tools.ietf.org/html/rfc6749#section-4 * @see http://tools.ietf.org/html/rfc6749#section-4
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4

View File

@ -10,7 +10,6 @@ use OAuth2\Storage\PublicKeyInterface;
use OAuth2\Storage\Memory; use OAuth2\Storage\Memory;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class JwtAccessToken extends AccessToken class JwtAccessToken extends AccessToken
@ -19,10 +18,13 @@ class JwtAccessToken extends AccessToken
protected $encryptionUtil; protected $encryptionUtil;
/** /**
* @param $config * @param PublicKeyInterface $publicKeyStorage -
* - store_encrypted_token_string (bool true) * @param AccessTokenStorageInterface $tokenStorage -
* whether the entire encrypted string is stored, * @param RefreshTokenInterface $refreshStorage -
* or just the token ID is stored * @param array $config - array with key store_encrypted_token_string (bool true)
* whether the entire encrypted string is stored,
* or just the token ID is stored
* @param EncryptionInterface $encryptionUtil -
*/ */
public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null) public function __construct(PublicKeyInterface $publicKeyStorage = null, AccessTokenStorageInterface $tokenStorage = null, RefreshTokenInterface $refreshStorage = null, array $config = array(), EncryptionInterface $encryptionUtil = null)
{ {
@ -45,46 +47,31 @@ class JwtAccessToken extends AccessToken
/** /**
* Handle the creation of access token, also issue refresh token if supported / desirable. * Handle the creation of access token, also issue refresh token if supported / desirable.
* *
* @param $client_id * @param mixed $client_id - Client identifier related to the access token.
* Client identifier related to the access token. * @param mixed $user_id - User ID associated with the access token
* @param $user_id * @param string $scope - (optional) Scopes to be stored in space-separated string.
* User ID associated with the access token * @param bool $includeRefreshToken - If true, a new refresh_token will be added to the response
* @param $scope * @return array - The access token
* (optional) Scopes to be stored in space-separated string.
* @param bool $includeRefreshToken
* If true, a new refresh_token will be added to the response
* *
* @see http://tools.ietf.org/html/rfc6749#section-5 * @see http://tools.ietf.org/html/rfc6749#section-5
* @ingroup oauth2_section_5 * @ingroup oauth2_section_5
*/ */
public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true) public function createAccessToken($client_id, $user_id, $scope = null, $includeRefreshToken = true)
{ {
// token to encrypt // payload to encrypt
$expires = time() + $this->config['access_lifetime']; $payload = $this->createPayload($client_id, $user_id, $scope);
$id = $this->generateAccessToken();
$jwtAccessToken = array(
'id' => $id, // for BC (see #591)
'jti' => $id,
'iss' => $this->config['issuer'],
'aud' => $client_id,
'sub' => $user_id,
'exp' => $expires,
'iat' => time(),
'token_type' => $this->config['token_type'],
'scope' => $scope
);
/* /*
* Encode the token data into a single access_token string * Encode the payload data into a single JWT access_token string
*/ */
$access_token = $this->encodeToken($jwtAccessToken, $client_id); $access_token = $this->encodeToken($payload, $client_id);
/* /*
* Save the token to a secondary storage. This is implemented on the * Save the token to a secondary storage. This is implemented on the
* OAuth2\Storage\JwtAccessToken side, and will not actually store anything, * OAuth2\Storage\JwtAccessToken side, and will not actually store anything,
* if no secondary storage has been supplied * if no secondary storage has been supplied
*/ */
$token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $jwtAccessToken['id']; $token_to_store = $this->config['store_encrypted_token_string'] ? $access_token : $payload['id'];
$this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope); $this->tokenStorage->setAccessToken($token_to_store, $client_id, $user_id, $this->config['access_lifetime'] ? time() + $this->config['access_lifetime'] : null, $scope);
// token to return to the client // token to return to the client
@ -114,6 +101,11 @@ class JwtAccessToken extends AccessToken
return $token; return $token;
} }
/**
* @param array $token
* @param mixed $client_id
* @return mixed
*/
protected function encodeToken(array $token, $client_id = null) protected function encodeToken(array $token, $client_id = null)
{ {
$private_key = $this->publicKeyStorage->getPrivateKey($client_id); $private_key = $this->publicKeyStorage->getPrivateKey($client_id);
@ -121,4 +113,31 @@ class JwtAccessToken extends AccessToken
return $this->encryptionUtil->encode($token, $private_key, $algorithm); return $this->encryptionUtil->encode($token, $private_key, $algorithm);
} }
/**
* This function can be used to create custom JWT payloads
*
* @param mixed $client_id - Client identifier related to the access token.
* @param mixed $user_id - User ID associated with the access token
* @param string $scope - (optional) Scopes to be stored in space-separated string.
* @return array - The access token
*/
protected function createPayload($client_id, $user_id, $scope = null)
{
// token to encrypt
$expires = time() + $this->config['access_lifetime'];
$id = $this->generateAccessToken();
return array(
'id' => $id, // for BC (see #591)
'jti' => $id,
'iss' => $this->config['issuer'],
'aud' => $client_id,
'sub' => $user_id,
'exp' => $expires,
'iat' => time(),
'token_type' => $this->config['token_type'],
'scope' => $scope
);
}
} }

View File

@ -4,5 +4,10 @@ namespace OAuth2\ResponseType;
interface ResponseTypeInterface interface ResponseTypeInterface
{ {
/**
* @param array $params
* @param mixed $user_id
* @return mixed
*/
public function getAuthorizeResponse($params, $user_id = null); public function getAuthorizeResponse($params, $user_id = null);
} }

View File

@ -2,19 +2,23 @@
namespace OAuth2; namespace OAuth2;
use InvalidArgumentException;
use OAuth2\Storage\Memory; use OAuth2\Storage\Memory;
use OAuth2\Storage\ScopeInterface as ScopeStorageInterface; use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
/** /**
* @see OAuth2\ScopeInterface * @see ScopeInterface
*/ */
class Scope implements ScopeInterface class Scope implements ScopeInterface
{ {
protected $storage; protected $storage;
/** /**
* @param mixed @storage * Constructor
* Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface *
* @param mixed $storage - Either an array of supported scopes, or an instance of OAuth2\Storage\ScopeInterface
*
* @throws InvalidArgumentException
*/ */
public function __construct($storage = null) public function __construct($storage = null)
{ {
@ -23,7 +27,7 @@ class Scope implements ScopeInterface
} }
if (!$storage instanceof ScopeStorageInterface) { if (!$storage instanceof ScopeStorageInterface) {
throw new \InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface"); throw new InvalidArgumentException("Argument 1 to OAuth2\Scope must be null, an array, or instance of OAuth2\Storage\ScopeInterface");
} }
$this->storage = $storage; $this->storage = $storage;
@ -32,12 +36,10 @@ class Scope implements ScopeInterface
/** /**
* Check if everything in required scope is contained in available scope. * Check if everything in required scope is contained in available scope.
* *
* @param $required_scope * @param string $required_scope - A space-separated string of scopes.
* A space-separated string of scopes. * @param string $available_scope - A space-separated string of scopes.
* * @return bool - TRUE if everything in required scope is contained in available scope and FALSE
* @return * if it isn't.
* TRUE if everything in required scope is contained in available scope,
* and FALSE if it isn't.
* *
* @see http://tools.ietf.org/html/rfc6749#section-7 * @see http://tools.ietf.org/html/rfc6749#section-7
* *
@ -54,11 +56,8 @@ class Scope implements ScopeInterface
/** /**
* Check if the provided scope exists in storage. * Check if the provided scope exists in storage.
* *
* @param $scope * @param string $scope - A space-separated string of scopes.
* A space-separated string of scopes. * @return bool - TRUE if it exists, FALSE otherwise.
*
* @return
* TRUE if it exists, FALSE otherwise.
*/ */
public function scopeExists($scope) public function scopeExists($scope)
{ {
@ -76,12 +75,20 @@ class Scope implements ScopeInterface
} }
} }
/**
* @param RequestInterface $request
* @return string
*/
public function getScopeFromRequest(RequestInterface $request) public function getScopeFromRequest(RequestInterface $request)
{ {
// "scope" is valid if passed in either POST or QUERY // "scope" is valid if passed in either POST or QUERY
return $request->request('scope', $request->query('scope')); return $request->request('scope', $request->query('scope'));
} }
/**
* @param null $client_id
* @return mixed
*/
public function getDefaultScope($client_id = null) public function getDefaultScope($client_id = null)
{ {
return $this->storage->getDefaultScope($client_id); return $this->storage->getDefaultScope($client_id);
@ -93,8 +100,7 @@ class Scope implements ScopeInterface
* In case OpenID Connect is used, these scopes must include: * In case OpenID Connect is used, these scopes must include:
* 'openid', offline_access'. * 'openid', offline_access'.
* *
* @return * @return array - An array of reserved scopes.
* An array of reserved scopes.
*/ */
public function getReservedScopes() public function getReservedScopes()
{ {

View File

@ -7,19 +7,17 @@ use OAuth2\Storage\ScopeInterface as ScopeStorageInterface;
/** /**
* Class to handle scope implementation logic * Class to handle scope implementation logic
* *
* @see OAuth2\Storage\ScopeInterface * @see \OAuth2\Storage\ScopeInterface
*/ */
interface ScopeInterface extends ScopeStorageInterface interface ScopeInterface extends ScopeStorageInterface
{ {
/** /**
* Check if everything in required scope is contained in available scope. * Check if everything in required scope is contained in available scope.
* *
* @param $required_scope * @param string $required_scope - A space-separated string of scopes.
* A space-separated string of scopes. * @param string $available_scope - A space-separated string of scopes.
* * @return boolean - TRUE if everything in required scope is contained in available scope and FALSE
* @return * if it isn't.
* TRUE if everything in required scope is contained in available scope,
* and FALSE if it isn't.
* *
* @see http://tools.ietf.org/html/rfc6749#section-7 * @see http://tools.ietf.org/html/rfc6749#section-7
* *
@ -30,11 +28,8 @@ interface ScopeInterface extends ScopeStorageInterface
/** /**
* Return scope info from request * Return scope info from request
* *
* @param OAuth2\RequestInterface * @param RequestInterface $request - Request object to check
* Request object to check * @return string - representation of requested scope
*
* @return
* string representation of requested scope
*/ */
public function getScopeFromRequest(RequestInterface $request); public function getScopeFromRequest(RequestInterface $request);
} }

View File

@ -30,25 +30,28 @@ use OAuth2\GrantType\UserCredentials;
use OAuth2\GrantType\ClientCredentials; use OAuth2\GrantType\ClientCredentials;
use OAuth2\GrantType\RefreshToken; use OAuth2\GrantType\RefreshToken;
use OAuth2\GrantType\AuthorizationCode; use OAuth2\GrantType\AuthorizationCode;
use OAuth2\Storage\ClientCredentialsInterface;
use OAuth2\Storage\ClientInterface;
use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage; use OAuth2\Storage\JwtAccessToken as JwtAccessTokenStorage;
use OAuth2\Storage\JwtAccessTokenInterface; use OAuth2\Storage\JwtAccessTokenInterface;
use InvalidArgumentException;
use LogicException;
/** /**
* Server class for OAuth2 * Server class for OAuth2
* This class serves as a convience class which wraps the other Controller classes * This class serves as a convience class which wraps the other Controller classes
* *
* @see OAuth2\Controller\ResourceController * @see \OAuth2\Controller\ResourceController
* @see OAuth2\Controller\AuthorizeController * @see \OAuth2\Controller\AuthorizeController
* @see OAuth2\Controller\TokenController * @see \OAuth2\Controller\TokenController
*/ */
class Server implements ResourceControllerInterface, class Server implements ResourceControllerInterface,
AuthorizeControllerInterface, AuthorizeControllerInterface,
TokenControllerInterface, TokenControllerInterface,
UserInfoControllerInterface UserInfoControllerInterface
{ {
// misc properties
/** /**
* @var Response * @var ResponseInterface
*/ */
protected $response; protected $response;
@ -62,7 +65,6 @@ class Server implements ResourceControllerInterface,
*/ */
protected $storages; protected $storages;
// servers
/** /**
* @var AuthorizeControllerInterface * @var AuthorizeControllerInterface
*/ */
@ -83,17 +85,34 @@ class Server implements ResourceControllerInterface,
*/ */
protected $userInfoController; protected $userInfoController;
// config classes /**
protected $grantTypes; * @var array
protected $responseTypes; */
protected $grantTypes = [];
/**
* @var array
*/
protected $responseTypes = [];
/**
* @var TokenTypeInterface
*/
protected $tokenType; protected $tokenType;
/** /**
* @var ScopeInterface * @var ScopeInterface
*/ */
protected $scopeUtil; protected $scopeUtil;
/**
* @var ClientAssertionTypeInterface
*/
protected $clientAssertionType; protected $clientAssertionType;
/**
* @var array
*/
protected $storageMap = array( protected $storageMap = array(
'access_token' => 'OAuth2\Storage\AccessTokenInterface', 'access_token' => 'OAuth2\Storage\AccessTokenInterface',
'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface', 'authorization_code' => 'OAuth2\Storage\AuthorizationCodeInterface',
@ -107,6 +126,9 @@ class Server implements ResourceControllerInterface,
'scope' => 'OAuth2\Storage\ScopeInterface', 'scope' => 'OAuth2\Storage\ScopeInterface',
); );
/**
* @var array
*/
protected $responseTypeMap = array( protected $responseTypeMap = array(
'token' => 'OAuth2\ResponseType\AccessTokenInterface', 'token' => 'OAuth2\ResponseType\AccessTokenInterface',
'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface', 'code' => 'OAuth2\ResponseType\AuthorizationCodeInterface',
@ -116,15 +138,15 @@ class Server implements ResourceControllerInterface,
); );
/** /**
* @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the * @param mixed $storage (array or OAuth2\Storage) - single object or array of objects implementing the
* required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum) * required storage types (ClientCredentialsInterface and AccessTokenInterface as a minimum)
* @param array $config specify a different token lifetime, token header name, etc * @param array $config specify a different token lifetime, token header name, etc
* @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens * @param array $grantTypes An array of OAuth2\GrantType\GrantTypeInterface to use for granting access tokens
* @param array $responseTypes Response types to use. array keys should be "code" and and "token" for * @param array $responseTypes Response types to use. array keys should be "code" and "token" for
* Access Token and Authorization Code response types * Access Token and Authorization Code response types
* @param \OAuth2\TokenType\TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac" * @param TokenTypeInterface $tokenType The token type object to use. Valid token types are "bearer" and "mac"
* @param \OAuth2\ScopeInterface $scopeUtil The scope utility class to use to validate scope * @param ScopeInterface $scopeUtil The scope utility class to use to validate scope
* @param \OAuth2\ClientAssertionType\ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic * @param ClientAssertionTypeInterface $clientAssertionType The method in which to verify the client identity. Default is HttpBasic
* *
* @ingroup oauth2_section_7 * @ingroup oauth2_section_7
*/ */
@ -172,6 +194,9 @@ class Server implements ResourceControllerInterface,
} }
} }
/**
* @return AuthorizeControllerInterface
*/
public function getAuthorizeController() public function getAuthorizeController()
{ {
if (is_null($this->authorizeController)) { if (is_null($this->authorizeController)) {
@ -181,6 +206,9 @@ class Server implements ResourceControllerInterface,
return $this->authorizeController; return $this->authorizeController;
} }
/**
* @return TokenController
*/
public function getTokenController() public function getTokenController()
{ {
if (is_null($this->tokenController)) { if (is_null($this->tokenController)) {
@ -190,6 +218,9 @@ class Server implements ResourceControllerInterface,
return $this->tokenController; return $this->tokenController;
} }
/**
* @return ResourceControllerInterface
*/
public function getResourceController() public function getResourceController()
{ {
if (is_null($this->resourceController)) { if (is_null($this->resourceController)) {
@ -199,6 +230,9 @@ class Server implements ResourceControllerInterface,
return $this->resourceController; return $this->resourceController;
} }
/**
* @return UserInfoControllerInterface
*/
public function getUserInfoController() public function getUserInfoController()
{ {
if (is_null($this->userInfoController)) { if (is_null($this->userInfoController)) {
@ -209,8 +243,6 @@ class Server implements ResourceControllerInterface,
} }
/** /**
* every getter deserves a setter
*
* @param AuthorizeControllerInterface $authorizeController * @param AuthorizeControllerInterface $authorizeController
*/ */
public function setAuthorizeController(AuthorizeControllerInterface $authorizeController) public function setAuthorizeController(AuthorizeControllerInterface $authorizeController)
@ -219,8 +251,6 @@ class Server implements ResourceControllerInterface,
} }
/** /**
* every getter deserves a setter
*
* @param TokenControllerInterface $tokenController * @param TokenControllerInterface $tokenController
*/ */
public function setTokenController(TokenControllerInterface $tokenController) public function setTokenController(TokenControllerInterface $tokenController)
@ -229,8 +259,6 @@ class Server implements ResourceControllerInterface,
} }
/** /**
* every getter deserves a setter
*
* @param ResourceControllerInterface $resourceController * @param ResourceControllerInterface $resourceController
*/ */
public function setResourceController(ResourceControllerInterface $resourceController) public function setResourceController(ResourceControllerInterface $resourceController)
@ -239,8 +267,6 @@ class Server implements ResourceControllerInterface,
} }
/** /**
* every getter deserves a setter
*
* @param UserInfoControllerInterface $userInfoController * @param UserInfoControllerInterface $userInfoController
*/ */
public function setUserInfoController(UserInfoControllerInterface $userInfoController) public function setUserInfoController(UserInfoControllerInterface $userInfoController)
@ -252,12 +278,8 @@ class Server implements ResourceControllerInterface,
* Return claims about the authenticated end-user. * Return claims about the authenticated end-user.
* This would be called from the "/UserInfo" endpoint as defined in the spec. * This would be called from the "/UserInfo" endpoint as defined in the spec.
* *
* @param $request - \OAuth2\RequestInterface * @param RequestInterface $request - Request object to grant access token
* Request object to grant access token * @param ResponseInterface $response - Response object containing error messages (failure) or user claims (success)
*
* @param $response - \OAuth2\ResponseInterface
* Response object containing error messages (failure) or user claims (success)
*
* @return ResponseInterface * @return ResponseInterface
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
@ -278,12 +300,8 @@ class Server implements ResourceControllerInterface,
* This would be called from the "/token" endpoint as defined in the spec. * This would be called from the "/token" endpoint as defined in the spec.
* Obviously, you can call your endpoint whatever you want. * Obviously, you can call your endpoint whatever you want.
* *
* @param $request - \OAuth2\RequestInterface * @param RequestInterface $request - Request object to grant access token
* Request object to grant access token * @param ResponseInterface $response - Response object containing error messages (failure) or access token (success)
*
* @param $response - \OAuth2\ResponseInterface
* Response object containing error messages (failure) or access token (success)
*
* @return ResponseInterface * @return ResponseInterface
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
@ -303,6 +321,11 @@ class Server implements ResourceControllerInterface,
return $this->response; return $this->response;
} }
/**
* @param RequestInterface $request - Request object to grant access token
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null) public function grantAccessToken(RequestInterface $request, ResponseInterface $response = null)
{ {
$this->response = is_null($response) ? new Response() : $response; $this->response = is_null($response) ? new Response() : $response;
@ -336,25 +359,18 @@ class Server implements ResourceControllerInterface,
* authorization server should call this function to redirect the user * authorization server should call this function to redirect the user
* appropriately. * appropriately.
* *
* @param $request * @param RequestInterface $request - The request should have the follow parameters set in the querystring:
* The request should have the follow parameters set in the querystring: * - response_type: The requested response: an access token, an authorization code, or both.
* - response_type: The requested response: an access token, an
* authorization code, or both.
* - client_id: The client identifier as described in Section 2. * - client_id: The client identifier as described in Section 2.
* - redirect_uri: An absolute URI to which the authorization server * - redirect_uri: An absolute URI to which the authorization server will redirect the user-agent to when the
* will redirect the user-agent to when the end-user authorization * end-user authorization step is completed.
* step is completed. * - scope: (optional) The scope of the resource request expressed as a list of space-delimited strings.
* - scope: (optional) The scope of the resource request expressed as a * - state: (optional) An opaque value used by the client to maintain state between the request and callback.
* list of space-delimited strings.
* - state: (optional) An opaque value used by the client to maintain
* state between the request and callback.
* @param ResponseInterface $response
* @param $is_authorized
* TRUE or FALSE depending on whether the user authorized the access.
* @param $user_id
* Identifier of user who authorized the client
* *
* @return Response * @param ResponseInterface $response - Response object
* @param bool $is_authorized - TRUE or FALSE depending on whether the user authorized the access.
* @param mixed $user_id - Identifier of user who authorized the client
* @return ResponseInterface
* *
* @see http://tools.ietf.org/html/rfc6749#section-4 * @see http://tools.ietf.org/html/rfc6749#section-4
* *
@ -371,14 +387,17 @@ class Server implements ResourceControllerInterface,
/** /**
* Pull the authorization request data out of the HTTP request. * Pull the authorization request data out of the HTTP request.
* - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it * - The redirect_uri is OPTIONAL as per draft 20. But your implementation can enforce it
* by setting $config['enforce_redirect'] to true. * by setting $config['enforce_redirect'] to true.
* - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that * - The state is OPTIONAL but recommended to enforce CSRF. Draft 21 states, however, that
* CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true. * CSRF protection is MANDATORY. You can enforce this by setting the $config['enforce_state'] to true.
* *
* The draft specifies that the parameters should be retrieved from GET, override the Response * The draft specifies that the parameters should be retrieved from GET, override the Response
* object to change this * object to change this
* *
* @return * @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @return bool
*
* The authorization parameters so the authorization server can prompt * The authorization parameters so the authorization server can prompt
* the user for approval if valid. * the user for approval if valid.
* *
@ -395,6 +414,12 @@ class Server implements ResourceControllerInterface,
return $value; return $value;
} }
/**
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @param string $scope - Scope
* @return mixed
*/
public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null) public function verifyResourceRequest(RequestInterface $request, ResponseInterface $response = null, $scope = null)
{ {
$this->response = is_null($response) ? new Response() : $response; $this->response = is_null($response) ? new Response() : $response;
@ -403,6 +428,11 @@ class Server implements ResourceControllerInterface,
return $value; return $value;
} }
/**
* @param RequestInterface $request - Request object
* @param ResponseInterface $response - Response object
* @return mixed
*/
public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null) public function getAccessTokenData(RequestInterface $request, ResponseInterface $response = null)
{ {
$this->response = is_null($response) ? new Response() : $response; $this->response = is_null($response) ? new Response() : $response;
@ -411,10 +441,14 @@ class Server implements ResourceControllerInterface,
return $value; return $value;
} }
/**
* @param GrantTypeInterface $grantType
* @param mixed $identifier
*/
public function addGrantType(GrantTypeInterface $grantType, $identifier = null) public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
{ {
if (!is_string($identifier)) { if (!is_string($identifier)) {
$identifier = $grantType->getQuerystringIdentifier(); $identifier = $grantType->getQueryStringIdentifier();
} }
$this->grantTypes[$identifier] = $grantType; $this->grantTypes[$identifier] = $grantType;
@ -428,11 +462,10 @@ class Server implements ResourceControllerInterface,
/** /**
* Set a storage object for the server * Set a storage object for the server
* *
* @param $storage * @param object $storage - An object implementing one of the Storage interfaces
* An object implementing one of the Storage interfaces * @param mixed $key - If null, the storage is set to the key of each storage interface it implements
* @param $key
* If null, the storage is set to the key of each storage interface it implements
* *
* @throws InvalidArgumentException
* @see storageMap * @see storageMap
*/ */
public function addStorage($storage, $key = null) public function addStorage($storage, $key = null)
@ -446,11 +479,11 @@ class Server implements ResourceControllerInterface,
// special logic to handle "client" and "client_credentials" strangeness // special logic to handle "client" and "client_credentials" strangeness
if ($key === 'client' && !isset($this->storages['client_credentials'])) { if ($key === 'client' && !isset($this->storages['client_credentials'])) {
if ($storage instanceof \OAuth2\Storage\ClientCredentialsInterface) { if ($storage instanceof ClientCredentialsInterface) {
$this->storages['client_credentials'] = $storage; $this->storages['client_credentials'] = $storage;
} }
} elseif ($key === 'client_credentials' && !isset($this->storages['client'])) { } elseif ($key === 'client_credentials' && !isset($this->storages['client'])) {
if ($storage instanceof \OAuth2\Storage\ClientInterface) { if ($storage instanceof ClientInterface) {
$this->storages['client'] = $storage; $this->storages['client'] = $storage;
} }
} }
@ -471,6 +504,12 @@ class Server implements ResourceControllerInterface,
} }
} }
/**
* @param ResponseTypeInterface $responseType
* @param mixed $key
*
* @throws InvalidArgumentException
*/
public function addResponseType(ResponseTypeInterface $responseType, $key = null) public function addResponseType(ResponseTypeInterface $responseType, $key = null)
{ {
$key = $this->normalizeResponseType($key); $key = $this->normalizeResponseType($key);
@ -497,6 +536,9 @@ class Server implements ResourceControllerInterface,
} }
} }
/**
* @return ScopeInterface
*/
public function getScopeUtil() public function getScopeUtil()
{ {
if (!$this->scopeUtil) { if (!$this->scopeUtil) {
@ -508,8 +550,6 @@ class Server implements ResourceControllerInterface,
} }
/** /**
* every getter deserves a setter
*
* @param ScopeInterface $scopeUtil * @param ScopeInterface $scopeUtil
*/ */
public function setScopeUtil($scopeUtil) public function setScopeUtil($scopeUtil)
@ -517,6 +557,10 @@ class Server implements ResourceControllerInterface,
$this->scopeUtil = $scopeUtil; $this->scopeUtil = $scopeUtil;
} }
/**
* @return AuthorizeControllerInterface
* @throws LogicException
*/
protected function createDefaultAuthorizeController() protected function createDefaultAuthorizeController()
{ {
if (!isset($this->storages['client'])) { if (!isset($this->storages['client'])) {
@ -541,6 +585,10 @@ class Server implements ResourceControllerInterface,
return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil()); return new AuthorizeController($this->storages['client'], $this->responseTypes, $config, $this->getScopeUtil());
} }
/**
* @return TokenControllerInterface
* @throws LogicException
*/
protected function createDefaultTokenController() protected function createDefaultTokenController()
{ {
if (0 == count($this->grantTypes)) { if (0 == count($this->grantTypes)) {
@ -562,7 +610,7 @@ class Server implements ResourceControllerInterface,
} }
if (!isset($this->storages['client'])) { if (!isset($this->storages['client'])) {
throw new \LogicException('You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server'); throw new LogicException("You must supply a storage object implementing OAuth2\Storage\ClientInterface to use the token server");
} }
$accessTokenResponseType = $this->getAccessTokenResponseType(); $accessTokenResponseType = $this->getAccessTokenResponseType();
@ -570,6 +618,10 @@ class Server implements ResourceControllerInterface,
return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil()); return new TokenController($accessTokenResponseType, $this->storages['client'], $this->grantTypes, $this->clientAssertionType, $this->getScopeUtil());
} }
/**
* @return ResourceControllerInterface
* @throws LogicException
*/
protected function createDefaultResourceController() protected function createDefaultResourceController()
{ {
if ($this->config['use_jwt_access_tokens']) { if ($this->config['use_jwt_access_tokens']) {
@ -590,6 +642,10 @@ class Server implements ResourceControllerInterface,
return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil()); return new ResourceController($this->tokenType, $this->storages['access_token'], $config, $this->getScopeUtil());
} }
/**
* @return UserInfoControllerInterface
* @throws LogicException
*/
protected function createDefaultUserInfoController() protected function createDefaultUserInfoController()
{ {
if ($this->config['use_jwt_access_tokens']) { if ($this->config['use_jwt_access_tokens']) {
@ -614,6 +670,9 @@ class Server implements ResourceControllerInterface,
return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil()); return new UserInfoController($this->tokenType, $this->storages['access_token'], $this->storages['user_claims'], $config, $this->getScopeUtil());
} }
/**
* @return Bearer
*/
protected function getDefaultTokenType() protected function getDefaultTokenType()
{ {
$config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name'))); $config = array_intersect_key($this->config, array_flip(explode(' ', 'token_param_name token_bearer_header_name')));
@ -621,6 +680,10 @@ class Server implements ResourceControllerInterface,
return new Bearer($config); return new Bearer($config);
} }
/**
* @return array
* @throws LogicException
*/
protected function getDefaultResponseTypes() protected function getDefaultResponseTypes()
{ {
$responseTypes = array(); $responseTypes = array();
@ -656,6 +719,10 @@ class Server implements ResourceControllerInterface,
return $responseTypes; return $responseTypes;
} }
/**
* @return array
* @throws LogicException
*/
protected function getDefaultGrantTypes() protected function getDefaultGrantTypes()
{ {
$grantTypes = array(); $grantTypes = array();
@ -692,6 +759,9 @@ class Server implements ResourceControllerInterface,
return $grantTypes; return $grantTypes;
} }
/**
* @return AccessToken
*/
protected function getAccessTokenResponseType() protected function getAccessTokenResponseType()
{ {
if (isset($this->responseTypes['token'])) { if (isset($this->responseTypes['token'])) {
@ -705,6 +775,9 @@ class Server implements ResourceControllerInterface,
return $this->createDefaultAccessTokenResponseType(); return $this->createDefaultAccessTokenResponseType();
} }
/**
* @return IdToken
*/
protected function getIdTokenResponseType() protected function getIdTokenResponseType()
{ {
if (isset($this->responseTypes['id_token'])) { if (isset($this->responseTypes['id_token'])) {
@ -714,6 +787,9 @@ class Server implements ResourceControllerInterface,
return $this->createDefaultIdTokenResponseType(); return $this->createDefaultIdTokenResponseType();
} }
/**
* @return IdTokenToken
*/
protected function getIdTokenTokenResponseType() protected function getIdTokenTokenResponseType()
{ {
if (isset($this->responseTypes['id_token token'])) { if (isset($this->responseTypes['id_token token'])) {
@ -725,6 +801,9 @@ class Server implements ResourceControllerInterface,
/** /**
* For Resource Controller * For Resource Controller
*
* @return JwtAccessTokenStorage
* @throws LogicException
*/ */
protected function createDefaultJwtAccessTokenStorage() protected function createDefaultJwtAccessTokenStorage()
{ {
@ -741,6 +820,9 @@ class Server implements ResourceControllerInterface,
/** /**
* For Authorize and Token Controllers * For Authorize and Token Controllers
*
* @return JwtAccessToken
* @throws LogicException
*/ */
protected function createDefaultJwtAccessTokenResponseType() protected function createDefaultJwtAccessTokenResponseType()
{ {
@ -763,10 +845,14 @@ class Server implements ResourceControllerInterface,
return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config); return new JwtAccessToken($this->storages['public_key'], $tokenStorage, $refreshStorage, $config);
} }
/**
* @return AccessToken
* @throws LogicException
*/
protected function createDefaultAccessTokenResponseType() protected function createDefaultAccessTokenResponseType()
{ {
if (!isset($this->storages['access_token'])) { if (!isset($this->storages['access_token'])) {
throw new \LogicException('You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server'); throw new LogicException("You must supply a response type implementing OAuth2\ResponseType\AccessTokenInterface, or a storage object implementing OAuth2\Storage\AccessTokenInterface to use the token server");
} }
$refreshStorage = null; $refreshStorage = null;
@ -780,13 +866,17 @@ class Server implements ResourceControllerInterface,
return new AccessToken($this->storages['access_token'], $refreshStorage, $config); return new AccessToken($this->storages['access_token'], $refreshStorage, $config);
} }
/**
* @return IdToken
* @throws LogicException
*/
protected function createDefaultIdTokenResponseType() protected function createDefaultIdTokenResponseType()
{ {
if (!isset($this->storages['user_claims'])) { if (!isset($this->storages['user_claims'])) {
throw new \LogicException('You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect'); throw new LogicException("You must supply a storage object implementing OAuth2\OpenID\Storage\UserClaimsInterface to use openid connect");
} }
if (!isset($this->storages['public_key'])) { if (!isset($this->storages['public_key'])) {
throw new \LogicException('You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect'); throw new LogicException("You must supply a storage object implementing OAuth2\Storage\PublicKeyInterface to use openid connect");
} }
$config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime'))); $config = array_intersect_key($this->config, array_flip(explode(' ', 'issuer id_lifetime')));
@ -794,11 +884,17 @@ class Server implements ResourceControllerInterface,
return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config); return new IdToken($this->storages['user_claims'], $this->storages['public_key'], $config);
} }
/**
* @return IdTokenToken
*/
protected function createDefaultIdTokenTokenResponseType() protected function createDefaultIdTokenTokenResponseType()
{ {
return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType()); return new IdTokenToken($this->getAccessTokenResponseType(), $this->getIdTokenResponseType());
} }
/**
* @throws InvalidArgumentException
*/
protected function validateOpenIdConnect() protected function validateOpenIdConnect()
{ {
$authCodeGrant = $this->getGrantType('authorization_code'); $authCodeGrant = $this->getGrantType('authorization_code');
@ -807,6 +903,10 @@ class Server implements ResourceControllerInterface,
} }
} }
/**
* @param string $name
* @return string
*/
protected function normalizeResponseType($name) protected function normalizeResponseType($name)
{ {
// for multiple-valued response types - make them alphabetical // for multiple-valued response types - make them alphabetical
@ -819,36 +919,60 @@ class Server implements ResourceControllerInterface,
return $name; return $name;
} }
/**
* @return mixed
*/
public function getResponse() public function getResponse()
{ {
return $this->response; return $this->response;
} }
/**
* @return array
*/
public function getStorages() public function getStorages()
{ {
return $this->storages; return $this->storages;
} }
/**
* @param string $name
* @return object|null
*/
public function getStorage($name) public function getStorage($name)
{ {
return isset($this->storages[$name]) ? $this->storages[$name] : null; return isset($this->storages[$name]) ? $this->storages[$name] : null;
} }
/**
* @return array
*/
public function getGrantTypes() public function getGrantTypes()
{ {
return $this->grantTypes; return $this->grantTypes;
} }
/**
* @param string $name
* @return object|null
*/
public function getGrantType($name) public function getGrantType($name)
{ {
return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null; return isset($this->grantTypes[$name]) ? $this->grantTypes[$name] : null;
} }
/**
* @return array
*/
public function getResponseTypes() public function getResponseTypes()
{ {
return $this->responseTypes; return $this->responseTypes;
} }
/**
* @param string $name
* @return object|null
*/
public function getResponseType($name) public function getResponseType($name)
{ {
// for multiple-valued response types - make them alphabetical // for multiple-valued response types - make them alphabetical
@ -857,23 +981,38 @@ class Server implements ResourceControllerInterface,
return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null; return isset($this->responseTypes[$name]) ? $this->responseTypes[$name] : null;
} }
/**
* @return TokenTypeInterface
*/
public function getTokenType() public function getTokenType()
{ {
return $this->tokenType; return $this->tokenType;
} }
/**
* @return ClientAssertionTypeInterface
*/
public function getClientAssertionType() public function getClientAssertionType()
{ {
return $this->clientAssertionType; return $this->clientAssertionType;
} }
/**
* @param string $name
* @param mixed $value
*/
public function setConfig($name, $value) public function setConfig($name, $value)
{ {
$this->config[$name] = $value; $this->config[$name] = $value;
} }
/**
* @param string $name
* @param mixed $default
* @return mixed
*/
public function getConfig($name, $default = null) public function getConfig($name, $default = null)
{ {
return isset($this->config[$name]) ? $this->config[$name] : $default; return isset($this->config[$name]) ? $this->config[$name] : $default;
} }
} }

View File

@ -15,17 +15,18 @@ interface AccessTokenInterface
* *
* We need to retrieve access token data as we create and verify tokens. * We need to retrieve access token data as we create and verify tokens.
* *
* @param $oauth_token * @param string $oauth_token - oauth_token to be check with.
* oauth_token to be check with.
* *
* @return * @return array|null - An associative array as below, and return NULL if the supplied oauth_token is invalid:
* An associative array as below, and return NULL if the supplied oauth_token * @code
* is invalid: * array(
* - expires: Stored expiration in unix timestamp. * 'expires' => $expires, // Stored expiration in unix timestamp.
* - client_id: (optional) Stored client identifier. * 'client_id' => $client_id, // (optional) Stored client identifier.
* - user_id: (optional) Stored user identifier. * 'user_id' => $user_id, // (optional) Stored user identifier.
* - scope: (optional) Stored scope values in space-separated string. * 'scope' => $scope, // (optional) Stored scope values in space-separated string.
* - id_token: (optional) Stored id_token (if "use_openid_connect" is true). * 'id_token' => $id_token // (optional) Stored id_token (if "use_openid_connect" is true).
* );
* @endcode
* *
* @ingroup oauth2_section_7 * @ingroup oauth2_section_7
*/ */
@ -36,11 +37,11 @@ interface AccessTokenInterface
* *
* We need to store access token data as we create and verify tokens. * We need to store access token data as we create and verify tokens.
* *
* @param $oauth_token oauth_token to be stored. * @param string $oauth_token - oauth_token to be stored.
* @param $client_id client identifier to be stored. * @param mixed $client_id - client identifier to be stored.
* @param $user_id user identifier to be stored. * @param mixed $user_id - user identifier to be stored.
* @param int $expires expiration to be stored as a Unix timestamp. * @param int $expires - expiration to be stored as a Unix timestamp.
* @param string $scope OPTIONAL Scopes to be stored in space-separated string. * @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* *
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
*/ */
@ -61,4 +62,4 @@ interface AccessTokenInterface
* @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x * @todo v2.0 include this method in interface. Omitted to maintain BC in v1.x
*/ */
//public function unsetAccessToken($access_token); //public function unsetAccessToken($access_token);
} }

View File

@ -59,12 +59,12 @@ interface AuthorizationCodeInterface
* *
* Required for OAuth2::GRANT_TYPE_AUTH_CODE. * Required for OAuth2::GRANT_TYPE_AUTH_CODE.
* *
* @param string $code Authorization code to be stored. * @param string $code - Authorization code to be stored.
* @param mixed $client_id Client identifier to be stored. * @param mixed $client_id - Client identifier to be stored.
* @param mixed $user_id User identifier to be stored. * @param mixed $user_id - User identifier to be stored.
* @param string $redirect_uri Redirect URI(s) to be stored in a space-separated string. * @param string $redirect_uri - Redirect URI(s) to be stored in a space-separated string.
* @param int $expires Expiration to be stored as a Unix timestamp. * @param int $expires - Expiration to be stored as a Unix timestamp.
* @param string $scope OPTIONAL Scopes to be stored in space-separated string. * @param string $scope - OPTIONAL Scopes to be stored in space-separated string.
* *
* @ingroup oauth2_section_4 * @ingroup oauth2_section_4
*/ */

View File

@ -7,24 +7,25 @@ use phpcassa\ColumnSlice;
use phpcassa\Connection\ConnectionPool; use phpcassa\Connection\ConnectionPool;
use OAuth2\OpenID\Storage\UserClaimsInterface; use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
use InvalidArgumentException;
/** /**
* Cassandra storage for all storage types * Cassandra storage for all storage types
* *
* To use, install "thobbs/phpcassa" via composer * To use, install "thobbs/phpcassa" via composer:
* <code> * <code>
* composer require thobbs/phpcassa:dev-master * composer require thobbs/phpcassa:dev-master
* </code> * </code>
* *
* Once this is done, instantiate the * Once this is done, instantiate the connection:
* <code> * <code>
* $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160')); * $cassandra = new \phpcassa\Connection\ConnectionPool('oauth2_server', array('127.0.0.1:9160'));
* </code> * </code>
* *
* Then, register the storage client: * Then, register the storage client:
* <code> * <code>
* $storage = new OAuth2\Storage\Cassandra($cassandra); * $storage = new OAuth2\Storage\Cassandra($cassandra);
* $storage->setClientDetails($client_id, $client_secret, $redirect_uri); * $storage->setClientDetails($client_id, $client_secret, $redirect_uri);
* </code> * </code>
* *
* @see test/lib/OAuth2/Storage/Bootstrap::getCassandraStorage * @see test/lib/OAuth2/Storage/Bootstrap::getCassandraStorage
@ -43,17 +44,23 @@ class Cassandra implements AuthorizationCodeInterface,
private $cache; private $cache;
/* The cassandra client */ /**
* @var ConnectionPool
*/
protected $cassandra; protected $cassandra;
/* Configuration array */ /**
* @var array
*/
protected $config; protected $config;
/** /**
* Cassandra Storage! uses phpCassa * Cassandra Storage! uses phpCassa
* *
* @param \phpcassa\ConnectionPool $cassandra * @param ConnectionPool|array $connection
* @param array $config * @param array $config
*
* @throws InvalidArgumentException
*/ */
public function __construct($connection = array(), array $config = array()) public function __construct($connection = array(), array $config = array())
{ {
@ -61,7 +68,7 @@ class Cassandra implements AuthorizationCodeInterface,
$this->cassandra = $connection; $this->cassandra = $connection;
} else { } else {
if (!is_array($connection)) { if (!is_array($connection)) {
throw new \InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array'); throw new InvalidArgumentException('First argument to OAuth2\Storage\Cassandra must be an instance of phpcassa\Connection\ConnectionPool or a configuration array');
} }
$connection = array_merge(array( $connection = array_merge(array(
'keyspace' => 'oauth2', 'keyspace' => 'oauth2',
@ -87,6 +94,10 @@ class Cassandra implements AuthorizationCodeInterface,
), $config); ), $config);
} }
/**
* @param $key
* @return bool|mixed
*/
protected function getValue($key) protected function getValue($key)
{ {
if (isset($this->cache[$key])) { if (isset($this->cache[$key])) {
@ -104,6 +115,12 @@ class Cassandra implements AuthorizationCodeInterface,
return json_decode($value, true); return json_decode($value, true);
} }
/**
* @param $key
* @param $value
* @param int $expire
* @return bool
*/
protected function setValue($key, $value, $expire = 0) protected function setValue($key, $value, $expire = 0)
{ {
$this->cache[$key] = $value; $this->cache[$key] = $value;
@ -131,6 +148,10 @@ class Cassandra implements AuthorizationCodeInterface,
return true; return true;
} }
/**
* @param $key
* @return bool
*/
protected function expireValue($key) protected function expireValue($key)
{ {
unset($this->cache[$key]); unset($this->cache[$key]);
@ -151,12 +172,25 @@ class Cassandra implements AuthorizationCodeInterface,
return false; return false;
} }
/* AuthorizationCodeInterface */ /**
* @param string $code
* @return bool|mixed
*/
public function getAuthorizationCode($code) public function getAuthorizationCode($code)
{ {
return $this->getValue($this->config['code_key'] . $code); return $this->getValue($this->config['code_key'] . $code);
} }
/**
* @param string $authorization_code
* @param mixed $client_id
* @param mixed $user_id
* @param string $redirect_uri
* @param int $expires
* @param string $scope
* @param string $id_token
* @return bool
*/
public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) public function setAuthorizationCode($authorization_code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{ {
return $this->setValue( return $this->setValue(
@ -166,6 +200,10 @@ class Cassandra implements AuthorizationCodeInterface,
); );
} }
/**
* @param string $code
* @return bool
*/
public function expireAuthorizationCode($code) public function expireAuthorizationCode($code)
{ {
$key = $this->config['code_key'] . $code; $key = $this->config['code_key'] . $code;
@ -174,7 +212,11 @@ class Cassandra implements AuthorizationCodeInterface,
return $this->expireValue($key); return $this->expireValue($key);
} }
/* UserCredentialsInterface */ /**
* @param string $username
* @param string $password
* @return bool
*/
public function checkUserCredentials($username, $password) public function checkUserCredentials($username, $password)
{ {
if ($user = $this->getUser($username)) { if ($user = $this->getUser($username)) {
@ -184,7 +226,13 @@ class Cassandra implements AuthorizationCodeInterface,
return false; return false;
} }
// plaintext passwords are bad! Override this for your application /**
* plaintext passwords are bad! Override this for your application
*
* @param array $user
* @param string $password
* @return bool
*/
protected function checkPassword($user, $password) protected function checkPassword($user, $password)
{ {
return $user['password'] == $this->hashPassword($password); return $user['password'] == $this->hashPassword($password);
@ -196,11 +244,19 @@ class Cassandra implements AuthorizationCodeInterface,
return sha1($password); return sha1($password);
} }
/**
* @param string $username
* @return array|bool|false
*/
public function getUserDetails($username) public function getUserDetails($username)
{ {
return $this->getUser($username); return $this->getUser($username);
} }
/**
* @param string $username
* @return array|bool
*/
public function getUser($username) public function getUser($username)
{ {
if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) { if (!$userInfo = $this->getValue($this->config['user_key'] . $username)) {
@ -213,6 +269,13 @@ class Cassandra implements AuthorizationCodeInterface,
), $userInfo); ), $userInfo);
} }
/**
* @param string $username
* @param string $password
* @param string $first_name
* @param string $last_name
* @return bool
*/
public function setUser($username, $password, $first_name = null, $last_name = null) public function setUser($username, $password, $first_name = null, $last_name = null)
{ {
$password = $this->hashPassword($password); $password = $this->hashPassword($password);
@ -223,7 +286,11 @@ class Cassandra implements AuthorizationCodeInterface,
); );
} }
/* ClientCredentialsInterface */ /**
* @param mixed $client_id
* @param string $client_secret
* @return bool
*/
public function checkClientCredentials($client_id, $client_secret = null) public function checkClientCredentials($client_id, $client_secret = null)
{ {
if (!$client = $this->getClientDetails($client_id)) { if (!$client = $this->getClientDetails($client_id)) {
@ -234,6 +301,10 @@ class Cassandra implements AuthorizationCodeInterface,
&& $client['client_secret'] == $client_secret; && $client['client_secret'] == $client_secret;
} }
/**
* @param $client_id
* @return bool
*/
public function isPublicClient($client_id) public function isPublicClient($client_id)
{ {
if (!$client = $this->getClientDetails($client_id)) { if (!$client = $this->getClientDetails($client_id)) {
@ -243,12 +314,24 @@ class Cassandra implements AuthorizationCodeInterface,
return empty($client['client_secret']); return empty($client['client_secret']);
} }
/* ClientInterface */ /**
* @param $client_id
* @return array|bool|mixed
*/
public function getClientDetails($client_id) public function getClientDetails($client_id)
{ {
return $this->getValue($this->config['client_key'] . $client_id); return $this->getValue($this->config['client_key'] . $client_id);
} }
/**
* @param $client_id
* @param null $client_secret
* @param null $redirect_uri
* @param null $grant_types
* @param null $scope
* @param null $user_id
* @return bool
*/
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
{ {
return $this->setValue( return $this->setValue(
@ -257,6 +340,11 @@ class Cassandra implements AuthorizationCodeInterface,
); );
} }
/**
* @param $client_id
* @param $grant_type
* @return bool
*/
public function checkRestrictedGrantType($client_id, $grant_type) public function checkRestrictedGrantType($client_id, $grant_type)
{ {
$details = $this->getClientDetails($client_id); $details = $this->getClientDetails($client_id);
@ -270,12 +358,23 @@ class Cassandra implements AuthorizationCodeInterface,
return true; return true;
} }
/* RefreshTokenInterface */ /**
* @param $refresh_token
* @return bool|mixed
*/
public function getRefreshToken($refresh_token) public function getRefreshToken($refresh_token)
{ {
return $this->getValue($this->config['refresh_token_key'] . $refresh_token); return $this->getValue($this->config['refresh_token_key'] . $refresh_token);
} }
/**
* @param $refresh_token
* @param $client_id
* @param $user_id
* @param $expires
* @param null $scope
* @return bool
*/
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
{ {
return $this->setValue( return $this->setValue(
@ -285,17 +384,32 @@ class Cassandra implements AuthorizationCodeInterface,
); );
} }
/**
* @param $refresh_token
* @return bool
*/
public function unsetRefreshToken($refresh_token) public function unsetRefreshToken($refresh_token)
{ {
return $this->expireValue($this->config['refresh_token_key'] . $refresh_token); return $this->expireValue($this->config['refresh_token_key'] . $refresh_token);
} }
/* AccessTokenInterface */ /**
* @param string $access_token
* @return array|bool|mixed|null
*/
public function getAccessToken($access_token) public function getAccessToken($access_token)
{ {
return $this->getValue($this->config['access_token_key'].$access_token); return $this->getValue($this->config['access_token_key'].$access_token);
} }
/**
* @param string $access_token
* @param mixed $client_id
* @param mixed $user_id
* @param int $expires
* @param null $scope
* @return bool
*/
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
{ {
return $this->setValue( return $this->setValue(
@ -305,12 +419,19 @@ class Cassandra implements AuthorizationCodeInterface,
); );
} }
/**
* @param $access_token
* @return bool
*/
public function unsetAccessToken($access_token) public function unsetAccessToken($access_token)
{ {
return $this->expireValue($this->config['access_token_key'] . $access_token); return $this->expireValue($this->config['access_token_key'] . $access_token);
} }
/* ScopeInterface */ /**
* @param $scope
* @return bool
*/
public function scopeExists($scope) public function scopeExists($scope)
{ {
$scope = explode(' ', $scope); $scope = explode(' ', $scope);
@ -322,6 +443,10 @@ class Cassandra implements AuthorizationCodeInterface,
return (count(array_diff($scope, $supportedScope)) == 0); return (count(array_diff($scope, $supportedScope)) == 0);
} }
/**
* @param null $client_id
* @return bool|mixed
*/
public function getDefaultScope($client_id = null) public function getDefaultScope($client_id = null)
{ {
if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) { if (is_null($client_id) || !$result = $this->getValue($this->config['scope_key'].'default:'.$client_id)) {
@ -331,6 +456,13 @@ class Cassandra implements AuthorizationCodeInterface,
return $result; return $result;
} }
/**
* @param $scope
* @param null $client_id
* @param string $type
* @return bool
* @throws \InvalidArgumentException
*/
public function setScope($scope, $client_id = null, $type = 'supported') public function setScope($scope, $client_id = null, $type = 'supported')
{ {
if (!in_array($type, array('default', 'supported'))) { if (!in_array($type, array('default', 'supported'))) {
@ -346,7 +478,11 @@ class Cassandra implements AuthorizationCodeInterface,
return $this->setValue($key, $scope); return $this->setValue($key, $scope);
} }
/*JWTBearerInterface */ /**
* @param $client_id
* @param $subject
* @return bool|null
*/
public function getClientKey($client_id, $subject) public function getClientKey($client_id, $subject)
{ {
if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) { if (!$jwt = $this->getValue($this->config['jwt_key'] . $client_id)) {
@ -360,6 +496,12 @@ class Cassandra implements AuthorizationCodeInterface,
return null; return null;
} }
/**
* @param $client_id
* @param $key
* @param null $subject
* @return bool
*/
public function setClientKey($client_id, $key, $subject = null) public function setClientKey($client_id, $key, $subject = null)
{ {
return $this->setValue($this->config['jwt_key'] . $client_id, array( return $this->setValue($this->config['jwt_key'] . $client_id, array(
@ -368,7 +510,10 @@ class Cassandra implements AuthorizationCodeInterface,
)); ));
} }
/*ScopeInterface */ /**
* @param $client_id
* @return bool|null
*/
public function getClientScope($client_id) public function getClientScope($client_id)
{ {
if (!$clientDetails = $this->getClientDetails($client_id)) { if (!$clientDetails = $this->getClientDetails($client_id)) {
@ -382,19 +527,38 @@ class Cassandra implements AuthorizationCodeInterface,
return null; return null;
} }
/**
* @param $client_id
* @param $subject
* @param $audience
* @param $expiration
* @param $jti
* @throws \Exception
*/
public function getJti($client_id, $subject, $audience, $expiration, $jti) public function getJti($client_id, $subject, $audience, $expiration, $jti)
{ {
//TODO: Needs cassandra implementation. //TODO: Needs cassandra implementation.
throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.'); throw new \Exception('getJti() for the Cassandra driver is currently unimplemented.');
} }
/**
* @param $client_id
* @param $subject
* @param $audience
* @param $expiration
* @param $jti
* @throws \Exception
*/
public function setJti($client_id, $subject, $audience, $expiration, $jti) public function setJti($client_id, $subject, $audience, $expiration, $jti)
{ {
//TODO: Needs cassandra implementation. //TODO: Needs cassandra implementation.
throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.'); throw new \Exception('setJti() for the Cassandra driver is currently unimplemented.');
} }
/* PublicKeyInterface */ /**
* @param string $client_id
* @return mixed
*/
public function getPublicKey($client_id = '') public function getPublicKey($client_id = '')
{ {
$public_key = $this->getValue($this->config['public_key_key'] . $client_id); $public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@ -407,6 +571,10 @@ class Cassandra implements AuthorizationCodeInterface,
} }
} }
/**
* @param string $client_id
* @return mixed
*/
public function getPrivateKey($client_id = '') public function getPrivateKey($client_id = '')
{ {
$public_key = $this->getValue($this->config['public_key_key'] . $client_id); $public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@ -419,6 +587,10 @@ class Cassandra implements AuthorizationCodeInterface,
} }
} }
/**
* @param null $client_id
* @return mixed|string
*/
public function getEncryptionAlgorithm($client_id = null) public function getEncryptionAlgorithm($client_id = null)
{ {
$public_key = $this->getValue($this->config['public_key_key'] . $client_id); $public_key = $this->getValue($this->config['public_key_key'] . $client_id);
@ -433,7 +605,11 @@ class Cassandra implements AuthorizationCodeInterface,
return 'RS256'; return 'RS256';
} }
/* UserClaimsInterface */ /**
* @param mixed $user_id
* @param string $claims
* @return array|bool
*/
public function getUserClaims($user_id, $claims) public function getUserClaims($user_id, $claims)
{ {
$userDetails = $this->getUserDetails($user_id); $userDetails = $this->getUserDetails($user_id);
@ -460,6 +636,11 @@ class Cassandra implements AuthorizationCodeInterface,
return $userClaims; return $userClaims;
} }
/**
* @param $claim
* @param $userDetails
* @return array
*/
protected function getUserClaim($claim, $userDetails) protected function getUserClaim($claim, $userDetails)
{ {
$userClaims = array(); $userClaims = array();
@ -476,5 +657,4 @@ class Cassandra implements AuthorizationCodeInterface,
return $userClaims; return $userClaims;
} }
}
}

View File

@ -328,4 +328,4 @@ class CouchbaseDB implements AuthorizationCodeInterface,
//TODO: Needs couchbase implementation. //TODO: Needs couchbase implementation.
throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.'); throw new \Exception('setJti() for the Couchbase driver is currently unimplemented.');
} }
} }

View File

@ -537,4 +537,4 @@ class DynamoDB implements
{ {
return null !== $value && '' !== $value; return null !== $value && '' !== $value;
} }
} }

View File

@ -6,7 +6,6 @@ use OAuth2\Encryption\EncryptionInterface;
use OAuth2\Encryption\Jwt; use OAuth2\Encryption\Jwt;
/** /**
*
* @author Brent Shaffer <bshafs at gmail dot com> * @author Brent Shaffer <bshafs at gmail dot com>
*/ */
class JwtAccessToken implements JwtAccessTokenInterface class JwtAccessToken implements JwtAccessTokenInterface
@ -85,4 +84,4 @@ class JwtAccessToken implements JwtAccessTokenInterface
return $tokenData; return $tokenData;
} }
} }

View File

@ -378,4 +378,4 @@ class Memory implements AuthorizationCodeInterface,
return 'RS256'; return 'RS256';
} }
} }

View File

@ -4,6 +4,7 @@ namespace OAuth2\Storage;
use OAuth2\OpenID\Storage\UserClaimsInterface; use OAuth2\OpenID\Storage\UserClaimsInterface;
use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface; use OAuth2\OpenID\Storage\AuthorizationCodeInterface as OpenIDAuthorizationCodeInterface;
use InvalidArgumentException;
/** /**
* Simple PDO storage for all storage types * Simple PDO storage for all storage types
@ -29,9 +30,22 @@ class Pdo implements
UserClaimsInterface, UserClaimsInterface,
OpenIDAuthorizationCodeInterface OpenIDAuthorizationCodeInterface
{ {
/**
* @var \PDO
*/
protected $db; protected $db;
/**
* @var array
*/
protected $config; protected $config;
/**
* @param mixed $connection
* @param array $config
*
* @throws InvalidArgumentException
*/
public function __construct($connection, $config = array()) public function __construct($connection, $config = array())
{ {
if (!$connection instanceof \PDO) { if (!$connection instanceof \PDO) {
@ -70,7 +84,11 @@ class Pdo implements
), $config); ), $config);
} }
/* OAuth2\Storage\ClientCredentialsInterface */ /**
* @param string $client_id
* @param null|string $client_secret
* @return bool
*/
public function checkClientCredentials($client_id, $client_secret = null) public function checkClientCredentials($client_id, $client_secret = null)
{ {
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
@ -81,6 +99,10 @@ class Pdo implements
return $result && $result['client_secret'] == $client_secret; return $result && $result['client_secret'] == $client_secret;
} }
/**
* @param string $client_id
* @return bool
*/
public function isPublicClient($client_id) public function isPublicClient($client_id)
{ {
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
@ -93,7 +115,10 @@ class Pdo implements
return empty($result['client_secret']); return empty($result['client_secret']);
} }
/* OAuth2\Storage\ClientInterface */ /**
* @param string $client_id
* @return array|mixed
*/
public function getClientDetails($client_id) public function getClientDetails($client_id)
{ {
$stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table'])); $stmt = $this->db->prepare(sprintf('SELECT * from %s where client_id = :client_id', $this->config['client_table']));
@ -102,6 +127,15 @@ class Pdo implements
return $stmt->fetch(\PDO::FETCH_ASSOC); return $stmt->fetch(\PDO::FETCH_ASSOC);
} }
/**
* @param string $client_id
* @param null|string $client_secret
* @param null|string $redirect_uri
* @param null|array $grant_types
* @param null|string $scope
* @param null|string $user_id
* @return bool
*/
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null) public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null)
{ {
// if it exists, update it. // if it exists, update it.
@ -114,6 +148,11 @@ class Pdo implements
return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id')); return $stmt->execute(compact('client_id', 'client_secret', 'redirect_uri', 'grant_types', 'scope', 'user_id'));
} }
/**
* @param $client_id
* @param $grant_type
* @return bool
*/
public function checkRestrictedGrantType($client_id, $grant_type) public function checkRestrictedGrantType($client_id, $grant_type)
{ {
$details = $this->getClientDetails($client_id); $details = $this->getClientDetails($client_id);
@ -127,7 +166,10 @@ class Pdo implements
return true; return true;
} }
/* OAuth2\Storage\AccessTokenInterface */ /**
* @param string $access_token
* @return array|bool|mixed|null
*/
public function getAccessToken($access_token) public function getAccessToken($access_token)
{ {
$stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table'])); $stmt = $this->db->prepare(sprintf('SELECT * from %s where access_token = :access_token', $this->config['access_token_table']));
@ -141,6 +183,14 @@ class Pdo implements
return $token; return $token;
} }
/**
* @param string $access_token
* @param mixed $client_id
* @param mixed $user_id
* @param int $expires
* @param string $scope
* @return bool
*/
public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null) public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
{ {
// convert expires to datestring // convert expires to datestring
@ -156,6 +206,10 @@ class Pdo implements
return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope')); return $stmt->execute(compact('access_token', 'client_id', 'user_id', 'expires', 'scope'));
} }
/**
* @param $access_token
* @return bool
*/
public function unsetAccessToken($access_token) public function unsetAccessToken($access_token)
{ {
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table'])); $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE access_token = :access_token', $this->config['access_token_table']));
@ -166,6 +220,10 @@ class Pdo implements
} }
/* OAuth2\Storage\AuthorizationCodeInterface */ /* OAuth2\Storage\AuthorizationCodeInterface */
/**
* @param string $code
* @return mixed
*/
public function getAuthorizationCode($code) public function getAuthorizationCode($code)
{ {
$stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table'])); $stmt = $this->db->prepare(sprintf('SELECT * from %s where authorization_code = :code', $this->config['code_table']));
@ -179,6 +237,16 @@ class Pdo implements
return $code; return $code;
} }
/**
* @param string $code
* @param mixed $client_id
* @param mixed $user_id
* @param string $redirect_uri
* @param int $expires
* @param string $scope
* @param string $id_token
* @return bool|mixed
*/
public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{ {
if (func_num_args() > 6) { if (func_num_args() > 6) {
@ -199,6 +267,16 @@ class Pdo implements
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope')); return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope'));
} }
/**
* @param string $code
* @param mixed $client_id
* @param mixed $user_id
* @param string $redirect_uri
* @param string $expires
* @param string $scope
* @param string $id_token
* @return bool
*/
private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null) private function setAuthorizationCodeWithIdToken($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
{ {
// convert expires to datestring // convert expires to datestring
@ -214,6 +292,10 @@ class Pdo implements
return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token')); return $stmt->execute(compact('code', 'client_id', 'user_id', 'redirect_uri', 'expires', 'scope', 'id_token'));
} }
/**
* @param string $code
* @return bool
*/
public function expireAuthorizationCode($code) public function expireAuthorizationCode($code)
{ {
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table'])); $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE authorization_code = :code', $this->config['code_table']));
@ -221,7 +303,11 @@ class Pdo implements
return $stmt->execute(compact('code')); return $stmt->execute(compact('code'));
} }
/* OAuth2\Storage\UserCredentialsInterface */ /**
* @param string $username
* @param string $password
* @return bool
*/
public function checkUserCredentials($username, $password) public function checkUserCredentials($username, $password)
{ {
if ($user = $this->getUser($username)) { if ($user = $this->getUser($username)) {
@ -231,12 +317,20 @@ class Pdo implements
return false; return false;
} }
/**
* @param string $username
* @return array|bool
*/
public function getUserDetails($username) public function getUserDetails($username)
{ {
return $this->getUser($username); return $this->getUser($username);
} }
/* UserClaimsInterface */ /**
* @param mixed $user_id
* @param string $claims
* @return array|bool
*/
public function getUserClaims($user_id, $claims) public function getUserClaims($user_id, $claims)
{ {
if (!$userDetails = $this->getUserDetails($user_id)) { if (!$userDetails = $this->getUserDetails($user_id)) {
@ -262,6 +356,11 @@ class Pdo implements
return $userClaims; return $userClaims;
} }
/**
* @param string $claim
* @param array $userDetails
* @return array
*/
protected function getUserClaim($claim, $userDetails) protected function getUserClaim($claim, $userDetails)
{ {
$userClaims = array(); $userClaims = array();
@ -275,7 +374,10 @@ class Pdo implements
return $userClaims; return $userClaims;
} }
/* OAuth2\Storage\RefreshTokenInterface */ /**
* @param string $refresh_token
* @return bool|mixed
*/
public function getRefreshToken($refresh_token) public function getRefreshToken($refresh_token)
{ {
$stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table'])); $stmt = $this->db->prepare(sprintf('SELECT * FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
@ -289,6 +391,14 @@ class Pdo implements
return $token; return $token;
} }
/**
* @param string $refresh_token
* @param mixed $client_id
* @param mixed $user_id
* @param string $expires
* @param string $scope
* @return bool
*/
public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null) public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
{ {
// convert expires to datestring // convert expires to datestring
@ -299,6 +409,10 @@ class Pdo implements
return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope')); return $stmt->execute(compact('refresh_token', 'client_id', 'user_id', 'expires', 'scope'));
} }
/**
* @param string $refresh_token
* @return bool
*/
public function unsetRefreshToken($refresh_token) public function unsetRefreshToken($refresh_token)
{ {
$stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table'])); $stmt = $this->db->prepare(sprintf('DELETE FROM %s WHERE refresh_token = :refresh_token', $this->config['refresh_token_table']));
@ -308,7 +422,13 @@ class Pdo implements
return $stmt->rowCount() > 0; return $stmt->rowCount() > 0;
} }
// plaintext passwords are bad! Override this for your application /**
* plaintext passwords are bad! Override this for your application
*
* @param array $user
* @param string $password
* @return bool
*/
protected function checkPassword($user, $password) protected function checkPassword($user, $password)
{ {
return $user['password'] == $this->hashPassword($password); return $user['password'] == $this->hashPassword($password);
@ -320,6 +440,10 @@ class Pdo implements
return sha1($password); return sha1($password);
} }
/**
* @param string $username
* @return array|bool
*/
public function getUser($username) public function getUser($username)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT * from %s where username=:username', $this->config['user_table']));
@ -335,6 +459,15 @@ class Pdo implements
), $userInfo); ), $userInfo);
} }
/**
* plaintext passwords are bad! Override this for your application
*
* @param string $username
* @param string $password
* @param string $firstName
* @param string $lastName
* @return bool
*/
public function setUser($username, $password, $firstName = null, $lastName = null) public function setUser($username, $password, $firstName = null, $lastName = null)
{ {
// do not store in plaintext // do not store in plaintext
@ -350,7 +483,10 @@ class Pdo implements
return $stmt->execute(compact('username', 'password', 'firstName', 'lastName')); return $stmt->execute(compact('username', 'password', 'firstName', 'lastName'));
} }
/* ScopeInterface */ /**
* @param string $scope
* @return bool
*/
public function scopeExists($scope) public function scopeExists($scope)
{ {
$scope = explode(' ', $scope); $scope = explode(' ', $scope);
@ -365,6 +501,10 @@ class Pdo implements
return false; return false;
} }
/**
* @param mixed $client_id
* @return null|string
*/
public function getDefaultScope($client_id = null) public function getDefaultScope($client_id = null)
{ {
$stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table'])); $stmt = $this->db->prepare(sprintf('SELECT scope FROM %s WHERE is_default=:is_default', $this->config['scope_table']));
@ -381,7 +521,11 @@ class Pdo implements
return null; return null;
} }
/* JWTBearerInterface */ /**
* @param mixed $client_id
* @param $subject
* @return string
*/
public function getClientKey($client_id, $subject) public function getClientKey($client_id, $subject)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT public_key from %s where client_id=:client_id AND subject=:subject', $this->config['jwt_table']));
@ -391,6 +535,10 @@ class Pdo implements
return $stmt->fetchColumn(); return $stmt->fetchColumn();
} }
/**
* @param mixed $client_id
* @return bool|null
*/
public function getClientScope($client_id) public function getClientScope($client_id)
{ {
if (!$clientDetails = $this->getClientDetails($client_id)) { if (!$clientDetails = $this->getClientDetails($client_id)) {
@ -404,6 +552,14 @@ class Pdo implements
return null; return null;
} }
/**
* @param mixed $client_id
* @param $subject
* @param $audience
* @param $expires
* @param $jti
* @return array|null
*/
public function getJti($client_id, $subject, $audience, $expires, $jti) public function getJti($client_id, $subject, $audience, $expires, $jti)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT * FROM %s WHERE issuer=:client_id AND subject=:subject AND audience=:audience AND expires=:expires AND jti=:jti', $this->config['jti_table']));
@ -423,6 +579,14 @@ class Pdo implements
return null; return null;
} }
/**
* @param mixed $client_id
* @param $subject
* @param $audience
* @param $expires
* @param $jti
* @return bool
*/
public function setJti($client_id, $subject, $audience, $expires, $jti) public function setJti($client_id, $subject, $audience, $expires, $jti)
{ {
$stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table'])); $stmt = $this->db->prepare(sprintf('INSERT INTO %s (issuer, subject, audience, expires, jti) VALUES (:client_id, :subject, :audience, :expires, :jti)', $this->config['jti_table']));
@ -430,7 +594,10 @@ class Pdo implements
return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti')); return $stmt->execute(compact('client_id', 'subject', 'audience', 'expires', 'jti'));
} }
/* PublicKeyInterface */ /**
* @param mixed $client_id
* @return mixed
*/
public function getPublicKey($client_id = null) public function getPublicKey($client_id = null)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT public_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
@ -441,6 +608,10 @@ class Pdo implements
} }
} }
/**
* @param mixed $client_id
* @return mixed
*/
public function getPrivateKey($client_id = null) public function getPrivateKey($client_id = null)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT private_key FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
@ -451,6 +622,10 @@ class Pdo implements
} }
} }
/**
* @param mixed $client_id
* @return string
*/
public function getEncryptionAlgorithm($client_id = null) public function getEncryptionAlgorithm($client_id = null)
{ {
$stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table'])); $stmt = $this->db->prepare($sql = sprintf('SELECT encryption_algorithm FROM %s WHERE client_id=:client_id OR client_id IS NULL ORDER BY client_id IS NOT NULL DESC', $this->config['public_key_table']));
@ -467,6 +642,9 @@ class Pdo implements
* DDL to create OAuth2 database and tables for PDO storage * DDL to create OAuth2 database and tables for PDO storage
* *
* @see https://github.com/dsquier/oauth2-server-php-mysql * @see https://github.com/dsquier/oauth2-server-php-mysql
*
* @param string $dbName
* @return string
*/ */
public function getBuildSql($dbName = 'oauth2_server_php') public function getBuildSql($dbName = 'oauth2_server_php')
{ {
@ -481,73 +659,73 @@ class Pdo implements
PRIMARY KEY (client_id) PRIMARY KEY (client_id)
); );
CREATE TABLE {$this->config['access_token_table']} ( CREATE TABLE {$this->config['access_token_table']} (
access_token VARCHAR(40) NOT NULL, access_token VARCHAR(40) NOT NULL,
client_id VARCHAR(80) NOT NULL, client_id VARCHAR(80) NOT NULL,
user_id VARCHAR(80), user_id VARCHAR(80),
expires TIMESTAMP NOT NULL, expires TIMESTAMP NOT NULL,
scope VARCHAR(4000), scope VARCHAR(4000),
PRIMARY KEY (access_token) PRIMARY KEY (access_token)
); );
CREATE TABLE {$this->config['code_table']} ( CREATE TABLE {$this->config['code_table']} (
authorization_code VARCHAR(40) NOT NULL, authorization_code VARCHAR(40) NOT NULL,
client_id VARCHAR(80) NOT NULL, client_id VARCHAR(80) NOT NULL,
user_id VARCHAR(80), user_id VARCHAR(80),
redirect_uri VARCHAR(2000), redirect_uri VARCHAR(2000),
expires TIMESTAMP NOT NULL, expires TIMESTAMP NOT NULL,
scope VARCHAR(4000), scope VARCHAR(4000),
id_token VARCHAR(1000), id_token VARCHAR(1000),
PRIMARY KEY (authorization_code) PRIMARY KEY (authorization_code)
); );
CREATE TABLE {$this->config['refresh_token_table']} ( CREATE TABLE {$this->config['refresh_token_table']} (
refresh_token VARCHAR(40) NOT NULL, refresh_token VARCHAR(40) NOT NULL,
client_id VARCHAR(80) NOT NULL, client_id VARCHAR(80) NOT NULL,
user_id VARCHAR(80), user_id VARCHAR(80),
expires TIMESTAMP NOT NULL, expires TIMESTAMP NOT NULL,
scope VARCHAR(4000), scope VARCHAR(4000),
PRIMARY KEY (refresh_token) PRIMARY KEY (refresh_token)
); );
CREATE TABLE {$this->config['user_table']} ( CREATE TABLE {$this->config['user_table']} (
username VARCHAR(80), username VARCHAR(80),
password VARCHAR(80), password VARCHAR(80),
first_name VARCHAR(80), first_name VARCHAR(80),
last_name VARCHAR(80), last_name VARCHAR(80),
email VARCHAR(80), email VARCHAR(80),
email_verified BOOLEAN, email_verified BOOLEAN,
scope VARCHAR(4000) scope VARCHAR(4000)
); );
CREATE TABLE {$this->config['scope_table']} ( CREATE TABLE {$this->config['scope_table']} (
scope VARCHAR(80) NOT NULL, scope VARCHAR(80) NOT NULL,
is_default BOOLEAN, is_default BOOLEAN,
PRIMARY KEY (scope) PRIMARY KEY (scope)
); );
CREATE TABLE {$this->config['jwt_table']} ( CREATE TABLE {$this->config['jwt_table']} (
client_id VARCHAR(80) NOT NULL, client_id VARCHAR(80) NOT NULL,
subject VARCHAR(80), subject VARCHAR(80),
public_key VARCHAR(2000) NOT NULL public_key VARCHAR(2000) NOT NULL
); );
CREATE TABLE {$this->config['jti_table']} ( CREATE TABLE {$this->config['jti_table']} (
issuer VARCHAR(80) NOT NULL, issuer VARCHAR(80) NOT NULL,
subject VARCHAR(80), subject VARCHAR(80),
audience VARCHAR(80), audiance VARCHAR(80),
expires TIMESTAMP NOT NULL, expires TIMESTAMP NOT NULL,
jti VARCHAR(2000) NOT NULL jti VARCHAR(2000) NOT NULL
); );
CREATE TABLE {$this->config['public_key_table']} ( CREATE TABLE {$this->config['public_key_table']} (
client_id VARCHAR(80), client_id VARCHAR(80),
public_key VARCHAR(2000), public_key VARCHAR(2000),
private_key VARCHAR(2000), private_key VARCHAR(2000),
encryption_algorithm VARCHAR(100) DEFAULT 'RS256' encryption_algorithm VARCHAR(100) DEFAULT 'RS256'
) )
"; ";
return $sql; return $sql;
} }
} }

View File

@ -10,7 +10,21 @@ namespace OAuth2\Storage;
*/ */
interface PublicKeyInterface interface PublicKeyInterface
{ {
/**
* @param mixed $client_id
* @return mixed
*/
public function getPublicKey($client_id = null); public function getPublicKey($client_id = null);
/**
* @param mixed $client_id
* @return mixed
*/
public function getPrivateKey($client_id = null); public function getPrivateKey($client_id = null);
/**
* @param mixed $client_id
* @return mixed
*/
public function getEncryptionAlgorithm($client_id = null); public function getEncryptionAlgorithm($client_id = null);
} }

View File

@ -37,15 +37,15 @@ interface UserCredentialsInterface
public function checkUserCredentials($username, $password); public function checkUserCredentials($username, $password);
/** /**
* @return * @param string $username - username to get details for
* ARRAY the associated "user_id" and optional "scope" values * @return array|false - the associated "user_id" and optional "scope" values
* This function MUST return FALSE if the requested user does not exist or is * This function MUST return FALSE if the requested user does not exist or is
* invalid. "scope" is a space-separated list of restricted scopes. * invalid. "scope" is a space-separated list of restricted scopes.
* @code * @code
* return array( * return array(
* "user_id" => USER_ID, // REQUIRED user_id to be stored with the authorization code or access token * "user_id" => USER_ID, // REQUIRED user_id to be stored with the authorization code or access token
* "scope" => SCOPE // OPTIONAL space-separated list of restricted scopes * "scope" => SCOPE // OPTIONAL space-separated list of restricted scopes
* ); * );
* @endcode * @endcode
*/ */
public function getUserDetails($username); public function getUserDetails($username);

View File

@ -2,7 +2,9 @@
namespace OAuth2; namespace OAuth2;
class AutoloadTest extends \PHPUnit_Framework_TestCase use PHPUnit\Framework\TestCase;
class AutoloadTest extends TestCase
{ {
public function testClassesExist() public function testClassesExist()
{ {

View File

@ -10,8 +10,9 @@ use OAuth2\GrantType\AuthorizationCode;
use OAuth2\Request; use OAuth2\Request;
use OAuth2\Response; use OAuth2\Response;
use OAuth2\Request\TestRequest; use OAuth2\Request\TestRequest;
use PHPUnit\Framework\TestCase;
class AuthorizeControllerTest extends \PHPUnit_Framework_TestCase class AuthorizeControllerTest extends TestCase
{ {
public function testNoClientIdResponse() public function testNoClientIdResponse()
{ {

Some files were not shown because too many files have changed in this diff Show More