Permalink
Browse files

Initial import.

  • Loading branch information...
0 parents commit 28ea0a56bfd44208a7b10ec08fa34cef86baef3e @mikesmullin committed Aug 7, 2011
@@ -0,0 +1,3 @@
+.hg/
+*.swo
+*.swp
@@ -0,0 +1,3 @@
+[submodule "vendors/oauth2-php"]
+ path = vendors/oauth2-php
+ url = git://github.com/mikesmullin/OAuth2-PHP.git
@@ -0,0 +1,70 @@
+CakePHP OAuth2 Server Plugin by Mike Smullin <mike@smullindesign.com>
+============
+
+** Host your own OAuth2 API Server Authentication system like Facebook, Twitter, etc. **
+
+Pre-requisites
+------------
+
+* CakePHP User Model defined in app
+* No conflict with using CakePHP Auth Component in plugin
+* CakePHP Migrations plugin installed
+
+Installation & Usage
+------------
+
+Place this directory in your plugins dir:
+
+ git submodule add git://github.com/mikesmullin/CakePHP-OAuth2-Server-Plugin.git ./app/plugins/oauth/
+
+Download the latest version of Tim Ridgley's oauth2-php into `./app/plugins/oauth/vendors/oauth2-php/`, as well:
+
+ git submodule update --init --recursive
+
+Add this line to your ./app/config/routes.php:
+
+ // include CakePHP-OAuth2-Server-Plugin routes
+ require_once App::pluginPath('OAuth2Server') .'config'. DS .'routes.php';
+
+Run this plugin's migrations (requires CakePHP Migrations plugin by CakeDC)
+
+ cake migration -plugin OAuth2Server
+
+Customize the file `./app/plugins/oauth/config/oauth.php` to fit your use case.
+
+Add this plugin's OAuth2 component to your AppController:
+
+ var $components = array('OAuth2Server.OAuth2');
+
+Add this override to your AppController:
+
+ /**
+ * Override isAuthorized() callback.
+ * Disables placeholder error and changes default to null,
+ * which has a special meaning for OAuth2Server plugin.
+ *
+ * @return Boolean
+ * null = check normally
+ * true = force allow without check
+ * false = force disallow without check
+ */
+ function isAuthorized() {
+ return null; // check normally
+ }
+
+Authentication verification happens automatically any time getCurrentUserId() is called:
+
+ try {
+ $this->OAuth2->getCurrentUserId(true); // true is optional and default; means throw exception on failure
+ } catch (Exception $e) {
+ // handle problems with access_token here
+ }
+
+Credits
+------------
+
+CakePHP-OAuth2-Server-Plugin is written by Mike Smullin and is released under the WTFPL.
+
+OAuth2-PHP is written by Tim Ridgely and licensed under MIT. see http://code.google.com/p/oauth2-php/
+
+CakePHP Migrations is written by CakeDC. see https://github.com/CakeDC/migrations
@@ -0,0 +1,14 @@
+<?php
+
+$config['OAuth2Server'] = array(
+ 'access_token_lifetime' => 60*60*12, // 12 hours
+ 'auth_code_lifetime' => 60*60*12, // 12 hours
+ 'refresh_token_lifetime' => 60*60*24*7*2, // 2 weeks
+
+ 'Auth' => array(
+ 'fields' => array(
+ 'username' => 'email',
+ 'password' => 'password'
+ )
+ ),
+);
@@ -0,0 +1,105 @@
+<?php
+class M4e3da3fa4ebc45749f8c0e391506eaf2 extends CakeMigration {
+
+/**
+ * Migration description
+ *
+ * @var string
+ * @access public
+ */
+ public $description = 'Create OAuth2 Server schema.';
+
+/**
+ * Actions to be performed
+ *
+ * @var array $migration
+ * @access public
+ */
+ public $migration = array(
+ 'up' => array(
+ 'create_table' => array(
+ 'o_auth2_server_clients' => array(
+ 'id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 20, 'key' => 'primary'),
+ 'secret' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 20),
+ 'redirect_uri' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 200),
+ 'description' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'indexes' => array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ ),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_unicode_ci', 'engine' => 'MyISAM'),
+ ),
+ 'o_auth2_server_codes' => array(
+ 'access_code' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'primary'),
+ 'client_id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 20),
+ 'redirect_uri' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 200),
+ 'expires' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'scope' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 250),
+ 'indexes' => array(
+ 'PRIMARY' => array('column' => 'access_code', 'unique' => 1),
+ ),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_unicode_ci', 'engine' => 'MyISAM'),
+ ),
+ 'o_auth2_server_tokens' => array(
+ 'token' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 40, 'key' => 'primary'),
+ 'client_id' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 20),
+ 'expires' => array('type' => 'integer', 'null' => false, 'default' => NULL),
+ 'scope' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 200),
+ 'username' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'device_id' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'indexes' => array(
+ 'PRIMARY' => array('column' => 'token', 'unique' => 1),
+ ),
+ 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_unicode_ci', 'engine' => 'MyISAM'),
+ ),
+ ),
+ ),
+ 'down' => array(
+ 'drop_table' => array(
+ 'o_auth2_server_clients', 'o_auth2_server_codes', 'o_auth2_server_tokens'
+ ),
+ ),
+ );
+
+/**
+ * Before migration callback
+ *
+ * @param string $direction, up or down direction of migration process
+ * @return boolean Should process continue
+ * @access public
+ */
+ public function before($direction) {
+ return true;
+ }
+
+/**
+ * After migration callback
+ *
+ * @param string $direction, up or down direction of migration process
+ * @return boolean Should process continue
+ * @access public
+ */
+ public function after($direction) {
+ $Query = $this->generateModel('Query', false, array('table' => false));
+ switch ($direction) {
+ case 'up':
+ return $Query->query(<<<MYSQL
+
+INSERT INTO `o_auth2_server_clients` (`id`, `secret`, `redirect_uri`, `description`)
+VALUES
+ ('test', 'test', '', 'Developer Sandbox'),
+ ('F4lnYzOteELJRKcWdKkG', 'r52745C8B7K351d71nw0', '', 'Web Application'),
+ ('DERUHwrBIDpc6fj2yys3', 'LU404t1Ul4qknIdVbwP4', '', 'iPhone Application'),
+ ('dSf8S9k4N3675I5HE63A', 'r58q7d4I7Fs3UKW152Xo', '', 'Android Application')
+;
+
+MYSQL
+ );
+ break;
+
+ case 'down':
+ break;
+ }
+ return true;
+ }
+}
+?>
@@ -0,0 +1,6 @@
+<?php
+$map = array(
+ 1 => array(
+ '20110806141600_create_o_auth2_server_schema' => 'M4e3da3fa4ebc45749f8c0e391506eaf2'),
+);
+?>
@@ -0,0 +1,10 @@
+<?php
+
+// GET /oauth/login
+Router::connect('/oauth/login', array('plugin' => 'o_auth2_server', 'controller' => 'o_auth2_server', 'action' => 'login', '[method]' => 'GET'));
+
+// POST /oauth/authorize
+Router::connect('/oauth/authorize', array('plugin' => 'o_auth2_server', 'controller' => 'o_auth2_server', 'action' => 'authorize', '[method]' => 'POST'));
+
+// POST /oauth/access_token
+Router::connect('/oauth/access_token', array('plugin' => 'o_auth2_server', 'controller' => 'o_auth2_server', 'action' => 'access_token', '[method]' => 'POST'));
@@ -0,0 +1,95 @@
+<?php
+
+class OAuth2Component extends Object {
+ /**
+ * Persistent reference to controller invoking this component.
+ */
+ var $controller;
+
+ /**
+ * initialize() callback.
+ * The initialize method is called before the controller's beforeFilter method.
+ */
+ function initialize(&$controller, $settings = array()) {
+ $this->controller = &$controller;
+
+ // include customized version of third-party class
+ App::import('Lib', 'OAuth2Server.OAuth2Lib');
+ $controller->OAuth2Lib = new OAuth2Lib(
+ Configure::read('OAuth2Server.access_token_lifetime'),
+ Configure::read('OAuth2Server.auth_code_lifetime'),
+ Configure::read('OAuth2Server.refresh_token_lifetime')
+ );
+ $controller->OAuth2Lib->controller = &$this->controller; // provide reference to OauthController object
+
+ if (method_exists($controller, 'isAuthorized')) {
+ $valid = $controller->isAuthorized();
+ switch (true) {
+ case $valid === true: // assume valid
+ return true;
+ break;
+ case $valid === false: // assume invalid
+ $controller->OAuth2Lib->send_401_unauthorized($realm = null, $scope = null, ERROR_INVALID_TOKEN);
+ break;
+ default:
+ case $valid === null: // check normally
+ $controller->OAuth2Lib->verify_access_token();
+ break;
+ }
+ }
+ else { // check normally
+ $controller->OAuth2Lib->verify_access_token();
+ }
+ }
+
+ /**
+ * Obtain information about the currently OAuth2 authenticated user.
+ * Similar to AuthComponent::user().
+ *
+ * @param String $field Name of field on User object to return.
+ * @return Mixed Requested data from User object.
+ */
+ function user($field) {
+ return $this->controller->OAuth2Lib->get_token_user($field);
+ }
+
+ /**
+ * Obtain the access_token used by the current user, if any.
+ *
+ * @return String access_token
+ */
+ function token() {
+ return $this->controller->OAuth2Lib->get_token();
+ }
+
+ /**
+ * Obtain the User.id of the currently OAuth2 authenticated user; or,
+ * throw an exception to be caught higher up.
+ *
+ * @param Boolean $throwExceptionOnFail (optional) Whether or not to throw
+ * an exception if user is not authenticated. Default is TRUE.
+ * @return Integer Current User.id
+ */
+ function getCurrentUserId($throwExceptionOnFail = true) {
+ // validate and cache to reduce db queries
+ static $current_user_id = null;
+ if (empty($_REQUEST['access_token'])) { // validate
+ if ($throwExceptionOnFail) {
+ throw new Exception(__('Missing access_token.', true));
+ }
+ return false;
+ }
+ else if ($current_user_id !== null) { // check cache
+ return $current_user_id;
+ }
+ else { // query db
+ if ($current_user_id = $this->controller->OAuth2->user('id')) {
+ return $current_user_id;
+ }
+ }
+ if ($throwExceptionOnFail) {
+ throw new Exception(__('Invalid or expired access_token.', true));
+ return false;
+ }
+ }
+}
@@ -0,0 +1,54 @@
+<?php
+
+class OAuth2ServerController extends OAuth2ServerAppController {
+ var $name = 'OAuth2Server';
+ var $uses = array();
+
+ /**
+ * isAuthorized() callback.
+ * Allow anonymous access to all actions of this controller.
+ */
+ function isAuthorized() {
+ return true;
+ }
+
+ /**
+ * Issue a new access_token to a formerly anonymous user.
+ * Used by apps to authenticate via RESTful APIs.
+ */
+ function access_token() {
+ try {
+ $this->OAuth2Lib->grant_access_token();
+ } catch(Exception $e) {
+ $this->fail($e);
+ }
+ }
+
+ /**
+ * Display an HTML login form to end-user.
+ * Used by third-party apps to authenticate via web browser. (Part 1 of 2)
+ */
+ function login() {
+ $this->helpers[] = 'Form';
+ }
+
+ /**
+ * Issue a new access_token to a formerly anonymous user.
+ * Used by third-party apps to authenticate via web browser. (Part 2 of 2)
+ */
+ function authorize() {
+ try {
+ $this->OAuth2Lib->finish_client_authorization(
+ (boolean) $this->OAuth2Lib->check_user_credentials($this->params['form']['client_id'], $this->params['form']['username'], $this->params['form']['password']),
+ $this->params['form']['response_type'],
+ $this->params['form']['client_id'],
+ $this->params['form']['redirect_uri'],
+ $this->params['form']['state'],
+ $this->params['form']['scope'],
+ $this->params['form']['username']
+ );
+ } catch(Exception $e) {
+ $this->fail($e);
+ }
+ }
+}
Oops, something went wrong.

0 comments on commit 28ea0a5

Please sign in to comment.