Created
July 17, 2012 09:05
-
-
Save ryo88c/3128218 to your computer and use it in GitHub Desktop.
Example of "OAuth 2.0 Bearer" end point, using the BEAR.Saturday
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once 'App.php'; | |
/** | |
* Web API Endpoint | |
* @see http://code.google.com/p/bear-project/ | |
* @see http://openid-foundation-japan.github.com/draft-ietf-oauth-v2-bearer-draft11.ja.html | |
*/ | |
class Page_Api_Index extends App_Page{ | |
/** @var array API が許可し、それぞれ対応するメソッド */ | |
protected $_methods = array('post' => 'create', 'put' => 'update', 'get' => 'read', 'delete' => 'delete'); | |
/** @var array API が許可する URI */ | |
protected $_enableURIs = array('me' => array('uri' => 'Me')); | |
/** @var array 認証が必要な場合にレスポンスヘッダに付与される Authorization ヘッダの内容 */ | |
protected $_authenticateHeaders = array( | |
'realm' => 'WebAPI OAuth 2.0 Bearer', | |
'scope' => null, | |
'error' => null, | |
'error_description' => null, | |
'error_uri' => null); | |
protected $_statusCode = 200; | |
public function onInject(){ | |
parent::onInject(); | |
$args = array('api' => null, 'method' => strtolower(getenv('REQUEST_METHOD'))); | |
if(!isset($_GET['api'])){ | |
if(isset($_SERVER['API'])){ | |
$_GET['api'] = preg_replace('!index.php$!', null, $_SERVER['API']); | |
$_GET['api'] = substr($_GET['api'], 5, strlen($_GET['api'])); | |
} | |
}else{ | |
$args['api'] = $_GET['api']; | |
} | |
$args['authorization'] = getenv('REDIRECT_HTTP_AUTHORIZATION'); | |
if(empty($args['authorization'])){ | |
$args['authorization'] = getenv('HTTP_AUTHORIZATION'); | |
} | |
if(empty($args['authorization']) && isset($_REQUEST['access_token'])){ | |
$args['authorization'] = sprintf('Bearer %s', $_REQUEST['access_token']); | |
} | |
if($args['method'] === 'post'){ | |
foreach($_POST as $name => $value){ | |
$args['values'][$name] = trim($value); | |
} | |
}elseif($args['method'] === 'put' || $args['method'] === 'delete'){ | |
$putdata = file_get_contents('php://input'); | |
parse_str($putdata, $putdata); | |
foreach($putdata as $name => $value){ | |
$args['values'][$name] = trim($value); | |
} | |
}else{ | |
unset($_GET['api']); | |
$args['values'] = $_GET; | |
} | |
$this->injectArgs($args); | |
} | |
public function onInit(array $args){ | |
foreach($this->_enableURIs as $regexp => $arg){ | |
if(preg_match(sprintf('!^%s$!', $regexp), $args['api'], $matches)){ | |
$arg = array_merge(array('uri' => null, | |
'options' => array(), 'query' => array()), $arg); | |
if(empty($arg['values'])){ | |
$arg['values'] = $args['values']; | |
}else{ | |
foreach($args['values'] as $name => $value){ | |
$arg['values'][$name] = trim($value); | |
} | |
} | |
unset($matches[0]); | |
foreach($matches as $i => $value){ | |
$value = trim($value); | |
if(!empty($value)){ | |
$arg['values'][$arg['query'][$i-1]] = trim($value); | |
} | |
} | |
unset($arg['query']); | |
if(preg_match('!^Bearer ([0-9a-f]{32})$!', $args['authorization'], $token)){ | |
$auth = Zend_Auth::getInstance(); | |
$auth->setStorage(new App_Auth_Storage(__CLASS__)); | |
$authAdapter = BEAR::dependency('App_Auth_Adapter_OAuth', array('token' => $token[1])); | |
$result = $this->_auth->authenticate($authAdapter); | |
if($result->isValid()){ | |
if(method_exists($this->_resource, $this->_methods[$args['method']])){ | |
$arg['uri'] = 'Api/'.$arg['uri']; | |
$ro = call_user_func(array(&$this->_resource, $this->_methods[$args['method']]), $arg); | |
if($ro !== false){ | |
$ro = $ro->request(); | |
$this->set('headers', $ro->getHeaders()); | |
$this->set('body', $ro->getBody()); | |
}else{ | |
throw new App_Exception_OAuth_InsufficientScope('This request is insufficient scope', $this->_authenticateHeaders); | |
} | |
} | |
}else{ | |
throw new App_Exception_OAuth_InvalidToken('The access token invalid', $this->_authenticateHeaders); | |
} | |
}else{ | |
$this->_statusCode = 401; | |
} | |
} | |
} | |
if(empty($this->_statusCode)){ | |
$this->end(404, 'Not found'); | |
} | |
} | |
public function onOutput(){ | |
$this->output('oauth', array( | |
'statusCode' => $this->_statusCode, | |
'authenticateHeaders' => $this->_authenticateHeaders | |
)); | |
} | |
} | |
App_Main::run('Page_Api_Index'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class App_Exception_OAuth_InsufficientScope extends BEAR_Exception{ | |
protected $_defaultMessage = 'This request is insufficient scope.'; | |
protected $_default = array('code' => 'insufficient_scope'); | |
public function __construct($msg = null, array $config = array()){ | |
if(empty($msg)){ | |
$msg = $this->_defaultMessage; | |
} | |
$config = array_merge($this->_default, (array) $config); | |
header(sprintf('WWW-Authenticate: Bearer realm="%s", error="%s", error_description="%s"', | |
$config['realm'], $config['code'], $msg)); | |
header('HTTP/1.1 403 Forbidden'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class App_Exception_OAuth_InvalidRequest extends BEAR_Exception{ | |
protected $_defaultMessage = 'URI is incorrect.'; | |
protected $_default = array('code' => 'invalid_request'); | |
public function __construct($msg = null, array $config = array()){ | |
if(empty($msg)){ | |
$msg = $this->_defaultMessage; | |
} | |
$config = array_merge($this->_default, (array) $config); | |
header(sprintf('WWW-Authenticate: Bearer realm="%s", error="%s", error_description="%s"', | |
$config['realm'], $config['code'], $msg)); | |
header('HTTP/1.1 400 Bad Request'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class App_Auth_Adapter_OAuth extends BEAR_Factory implements Zend_Auth_Adapter_Interface{ | |
public function factory(){ | |
return $this; | |
} | |
public function authenticate(){ | |
$user = $messages = $code = null; | |
if(!empty($this->_config['token'])){ | |
$user = $this->_resource->read(array('uri' => 'Db/User/Authentication', | |
'values' => array('token' => $this->_config['token'])))->getBody(); | |
if(!empty($user)){ | |
$messages = array(__('Logined.')); | |
$code = Zend_Auth_Result::SUCCESS; | |
$user['remoteAddr'] = getenv('REMOTE_ADDR'); | |
$user['userAgent'] = getenv('HTTP_USER_AGENT'); | |
}else{ | |
$code = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; | |
} | |
}else{ | |
$code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; | |
} | |
return new Zend_Auth_Result($code, $user, $messages); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** OAuth ヘッダー & JSON 出力 | |
* @param array $values 値 | |
* @param array $options オプション | |
* @return BEAR_Ro | |
*/ | |
function outputOAuth($values, array $options){ | |
$app = BEAR::get('app'); | |
$ro = BEAR::factory('App_Ro_Http'); | |
$ro->setCode($options['statusCode']); | |
$headers = array(); | |
if(in_array($options['statusCode'], array(401, 403))){ | |
$rows = array(); | |
foreach($options['authenticateHeaders'] as $name => $value){ | |
if(!empty($value)){ | |
$rows[] = sprintf('%s="%s"', $name, $value); | |
} | |
} | |
$headers[] = sprintf('WWW-Authenticate: Bearer %s', implode(", ", $rows)); | |
} | |
$body = empty($values)? null: json_encode($values); | |
$ro->setBody($body); | |
$ro->setHeaders($headers); | |
return $ro; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class App_Auth_Storage extends Zend_Auth_Storage_Session{ | |
private $_storage = array(); | |
public function isEmpty(){ | |
return !isset($this->_storage[$this->_namespace]) || is_null($this->_storage[$this->_namespace]); | |
} | |
public function read(){ | |
return $this->_storage[$this->_namespace]; | |
} | |
public function write($contents){ | |
$this->_storage[$this->_namespace] = $contents; | |
} | |
public function clear(){ | |
$this->_storage[$this->_namespace] = null; | |
} | |
public function __construct($namespace = self::NAMESPACE_DEFAULT, $member = self::MEMBER_DEFAULT){ | |
$this->_namespace = $namespace; | |
$this->_member = $member; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment