├── guide
└── oauthz
│ ├── menu.md
│ ├── api.md
│ ├── index.md
│ ├── extension.md
│ ├── server.md
│ ├── client.md
│ └── demo.md
├── license
├── doc
├── oauth-er.png
├── oauth-mysql.sql
├── oauth-oracle.sql
├── oauth-postgresql.sql
└── oauth-mssql.sql
├── changelog.txt
├── views
├── oauthz-client.php
├── oauthz-server-signin.php
├── oauthz-server-xrds.php
├── oauthz-server.php
├── oauthz-client-response.php
├── oauthz-server-authorize.php
├── oauthz-server-client.php
├── oauthz-server-error.php
├── oauthz-server-register.php
└── oauthz-template.php
├── roadmap.md
├── classes
├── model
│ ├── oauthz.php
│ └── oauthz
│ │ ├── authorize.php
│ │ ├── token.php
│ │ └── client.php
├── oauthz
│ ├── exception
│ │ ├── authorize.php
│ │ ├── token.php
│ │ └── access.php
│ ├── token
│ │ ├── bearer.php
│ │ ├── basic.php
│ │ ├── mac.php
│ │ └── digest.php
│ ├── extension.php
│ ├── authentication.php
│ ├── core.php
│ ├── server.php
│ ├── exception.php
│ ├── extension
│ │ ├── code.php
│ │ ├── assertion.php
│ │ ├── authorization
│ │ │ └── code.php
│ │ ├── refresh
│ │ │ └── token.php
│ │ ├── client
│ │ │ └── credentials.php
│ │ ├── password.php
│ │ └── token.php
│ ├── controller.php
│ ├── token.php
│ ├── api.php
│ └── client.php
├── oauthz.php
└── controller
│ ├── server.php
│ ├── authorize.php
│ ├── client.php
│ ├── api.php
│ └── oauth.php
├── config
├── userguide.php
├── oauth-api.php
├── oauth-client.php
└── oauth-server.php
├── messages
└── oauthz.php
├── README.md
└── i18n
└── en.php
/guide/oauthz/menu.md:
--------------------------------------------------------------------------------
1 | ## [Oauthy]()
2 | - [Demo](demo)
3 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yahasana/kohana-oauthz/HEAD/license
--------------------------------------------------------------------------------
/guide/oauthz/api.md:
--------------------------------------------------------------------------------
1 | ## Develop Protected Web Service API ##
2 |
3 |
4 |
--------------------------------------------------------------------------------
/doc/oauth-er.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Yahasana/kohana-oauthz/HEAD/doc/oauth-er.png
--------------------------------------------------------------------------------
/guide/oauthz/index.md:
--------------------------------------------------------------------------------
1 | # Oauthy
2 |
3 | OAuth protocol 2.0 implement for Kohana 3, including server and client
--------------------------------------------------------------------------------
/changelog.txt:
--------------------------------------------------------------------------------
1 |
2 | Dec 20, 2011
3 | 1) Refactor to Oauth 2.0 rev 22
4 | 2) authorization code with bearer token_type support
--------------------------------------------------------------------------------
/guide/oauthz/extension.md:
--------------------------------------------------------------------------------
1 | ## Extension ##
2 |
3 | ### Customize extension ###
4 |
5 | ### Develop new extension ###
6 |
--------------------------------------------------------------------------------
/guide/oauthz/server.md:
--------------------------------------------------------------------------------
1 | ## Server ##
2 |
3 | ### Install and configuration ###
4 |
5 | ### Resources management interface ###
--------------------------------------------------------------------------------
/guide/oauthz/client.md:
--------------------------------------------------------------------------------
1 | ## Client component ##
2 |
3 | ### Install and configuration ###
4 |
5 | ### Communicate with OAuth 2 server ###
6 |
--------------------------------------------------------------------------------
/views/oauthz-client.php:
--------------------------------------------------------------------------------
1 |
2 | Do you want to import you personal information from example.com ?
3 | Yeah, of cause ! Let's go
4 |
--------------------------------------------------------------------------------
/roadmap.md:
--------------------------------------------------------------------------------
1 | #Development roadmap
2 |
3 | ## Server mode ##
4 |
5 | 1. Extensions
6 | code, token, authorization_code, implicit, client credentials
7 |
8 | 2. Authentications
9 | bear, mac
10 |
11 | ### Model process ###
12 |
13 | ### Client profiles support ###
14 |
15 |
16 | ## Client mode ##
17 |
18 |
19 | ## Demo app ##
20 |
21 |
22 | ## User guide book ##
23 |
--------------------------------------------------------------------------------
/views/oauthz-server-signin.php:
--------------------------------------------------------------------------------
1 | get('user'))
3 | {
4 | $usermail = $user['mail'];
5 | }
6 | else
7 | {
8 | $usermail = '';
9 | }
10 | ?>
--------------------------------------------------------------------------------
/views/oauthz-server-xrds.php:
--------------------------------------------------------------------------------
1 | ';
4 | ?>
6 | 2011-05-10T00:00:00Z
7 | http://oauth
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/classes/model/oauthz.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Kohana_Model
11 | * *
12 | */
13 | class Model_Oauthz extends Kohana_Model {
14 |
15 | protected $_db = 'default';
16 |
17 | public static function factory($name, $db = NULL)
18 | {
19 | // Add the model prefix
20 | $class = 'Model_Oauthz_'.$name;
21 |
22 | return new $class($db);
23 | }
24 |
25 | } // END Model_Oauthz
26 |
--------------------------------------------------------------------------------
/config/userguide.php:
--------------------------------------------------------------------------------
1 | array(
7 |
8 | // This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename'
9 | 'oauthy' => array(
10 |
11 | // Whether this modules userguide pages should be shown
12 | 'enabled' => TRUE,
13 |
14 | // The name that should show up on the userguide index page
15 | 'name' => 'oauthy',
16 |
17 | // A short description of this module, shown on the index page
18 | 'description' => 'Oauth server and client for Kohana',
19 | )
20 | )
21 | );
--------------------------------------------------------------------------------
/messages/oauthz.php:
--------------------------------------------------------------------------------
1 | ':field must not be empty',
5 | 'matches' => ':field must be the same as :param1',
6 | 'regex' => ':field does not match the required format',
7 | 'exact_length' => ':field must be exactly :param1 characters long',
8 | 'min_length' => ':field must be at least :param1 characters long',
9 | 'max_length' => ':field must be less than :param1 characters long',
10 | 'in_array' => ':field must be one of the available options',
11 | 'digit' => ':field must be a digit',
12 | 'decimal' => ':field must be a decimal with :param1 places',
13 | 'range' => ':field must be within the range of :param1 to :param2',
14 | );
--------------------------------------------------------------------------------
/classes/oauthz/exception/authorize.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | class Oauthz_Exception_Authorize extends Oauthz_Exception {
13 |
14 | public function __construct($message, array $state = NULL, $code = 0)
15 | {
16 | $error_description = I18n::get('Authorization Errors Response');
17 |
18 | $this->error_description = $error_description[$message];
19 |
20 | // Pass the message to the parent
21 | parent::__construct($message, $state, $code);
22 | }
23 |
24 | } // END Oauthz_Exception_Authorize
25 |
--------------------------------------------------------------------------------
/classes/oauthz/exception/token.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | class Oauthz_Exception_Token extends Oauthz_Exception {
13 |
14 | public function __construct($message, array $state = NULL, $code = 0)
15 | {
16 | $error_description = I18n::get('Token Errors Response');
17 |
18 | $this->error_description = $error_description[$message];
19 |
20 | // Pass the message to the parent
21 | parent::__construct($message, $state, $code);
22 | }
23 |
24 | } // END Oauthz_Exception_Token
25 |
--------------------------------------------------------------------------------
/classes/oauthz/exception/access.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | class Oauthz_Exception_Access extends Oauthz_Exception {
13 |
14 | public function __construct($message, array $state = NULL, $code = 0)
15 | {
16 | $error_description = I18n::get('Access Errors Response');
17 |
18 | $this->error_description = $error_description[$message];
19 |
20 | // Pass the message to the parent
21 | parent::__construct($message, $state, $code);
22 | }
23 |
24 | } // END Oauthz_Exception_Access
25 |
--------------------------------------------------------------------------------
/views/oauthz-server.php:
--------------------------------------------------------------------------------
1 | Applications list you have registered
4 | API Key API Secret Redirect URI Scope SSH Key OP
5 |
9 |
10 | DEL render(); ?>
13 |
14 | Register another request indentifier
15 |
--------------------------------------------------------------------------------
/classes/oauthz.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | abstract class Oauthz extends Oauthz_Core {
13 |
14 | public static function get($key = NULL, $default = NULL)
15 | {
16 | if ($key === NULL)
17 | {
18 | $default = Request::$method === 'POST' ? $_POST : $_GET;
19 | }
20 | else
21 | {
22 | $data = Request::$method === 'POST' ? $_POST : $_GET;
23 |
24 | if(isset($data[$key])) $default = $data[$key];
25 | }
26 | return $default;
27 | }
28 |
29 | public static function is_login()
30 | {
31 | return Session::instance()->get('user') OR Cookie::get('user');
32 | }
33 |
34 | } // END Oauthz
35 |
--------------------------------------------------------------------------------
/classes/controller/server.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Server
11 | * *
12 | */
13 | class Controller_Server extends Oauthz_Server {
14 |
15 | public function __construct(Request $request)
16 | {
17 | if( ! Session::instance()->get('user'))
18 | {
19 | $request->redirect('oauth/signin');
20 | }
21 |
22 | parent::__construct($request);
23 | }
24 |
25 | public function action_index()
26 | {
27 | $server = new Model_Oauthz_Client;
28 |
29 | $data = $server->lists(array('user_id' => $_SESSION['user']['uid']));
30 |
31 | $this->template->content = new View('oauthz-server', $data);
32 |
33 | $this->request->response = $this->template->render();
34 | }
35 |
36 | } // END Controller Consumer
37 |
--------------------------------------------------------------------------------
/views/oauthz-client-response.php:
--------------------------------------------------------------------------------
1 |
4 | The first request and response
5 | URI = $first['uri'] ?> ☜ Click! to access it directly
6 | access_token = $first['token'] ?>
7 | response [json] = $first['info'] ?>
8 |
9 |
10 | The second request and response
11 | URI = $second['uri'] ?> ☜ Click! to access it directly
12 | access_token = $second['token'] ?>
13 | response [json] = $second['info'] ?>
14 |
15 |
16 |
17 | Look cool, hum
18 | But uham, do not try to refresh this page to refetch these info!
19 | if you do, yup please have a try.
--------------------------------------------------------------------------------
/classes/oauthz/token/bearer.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Authentication
11 | * *
12 | */
13 | class Oauthz_Token_Bearer extends Oauthz_Authentication {
14 |
15 | public function verify($token)
16 | {
17 | if($data = static::parse())
18 | {
19 | // TODO
20 | }
21 |
22 | return $data;
23 | }
24 |
25 | public static function parse($digest = NULL)
26 | {
27 | if ($digest === NULL AND isset($_SERVER['HTTP_AUTHORIZATION'])
28 | AND strpos(strtolower($_SERVER['HTTP_AUTHORIZATION']), 'bearer') === 0)
29 | {
30 | $params = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 7)), 2);
31 |
32 | // TODO
33 | }
34 |
35 | return empty($data) ? FALSE : $data;
36 | }
37 |
38 | } // END Oauthz_Token_Bearer
39 |
--------------------------------------------------------------------------------
/classes/controller/authorize.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Controller
11 | * *
12 | */
13 | class Controller_Authorize extends Oauthz_Controller {
14 |
15 | public function action_index()
16 | {
17 | //~ are you sure to access your infomation data from webservice sp.example.com
18 | //~ Yes - send request token to sp.example.com
19 | //~ $uri = 'http://localhost/oauth/request';
20 | //$token = parent::request_token();
21 |
22 | //~ $uri = 'http://localhost/oauth/authorize';
23 | parent::action_authorize();
24 | }
25 |
26 | public function action_okay()
27 | {
28 | echo 'ha ha hahahha!';
29 | }
30 |
31 | public function action_test()
32 | {
33 | extract(array('hel'=>'helo'),EXTR_PREFIX_ALL,'this->');
34 | $this->request->response = $this->_hel;
35 | }
36 |
37 | } // END Controller Consumer
38 |
--------------------------------------------------------------------------------
/classes/oauthz/extension.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | abstract class Oauthz_Extension {
13 |
14 | /**
15 | * OPTION if the "state" parameter was present in the client authorization request.
16 | *
17 | * @access protected
18 | * @var string $state
19 | */
20 | protected $state;
21 |
22 | /**
23 | * Create grant_type or token_type object
24 | *
25 | * @access public
26 | * @param string $type
27 | * @param array $args
28 | * @return mix
29 | */
30 | public static function factory($type, array $args)
31 | {
32 | $type = 'Oauthz_Extension_'.$type;
33 |
34 | if(class_exists($type))
35 | {
36 | return new $type($args);
37 | }
38 |
39 | return FALSE;
40 | }
41 |
42 | /**
43 | * Obtain token
44 | *
45 | * @access public
46 | * @return mix
47 | */
48 | abstract public function execute();
49 |
50 | } // END Oauthz_Extension
51 |
--------------------------------------------------------------------------------
/views/oauthz-server-authorize.php:
--------------------------------------------------------------------------------
1 | OAuth Test Client
2 | Note: we don't store any of the information you type in.
3 | do you want to let the to access your information?
7 | Approve access
8 | Deny access Service list you have register
5 | client_id redirect_uri confirm_type client_desc OP
6 | DEL
10 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Authentication
11 | * *
12 | */
13 | class Oauthz_Token_Basic extends Oauthz_Authentication {
14 |
15 | public function verify($token)
16 | {
17 | if($data = static::parse())
18 | {
19 | $data = $data['client_id'] === $token['client_id'] AND $data['client_secret'] === $token['client_secret'];
20 | }
21 |
22 | return $data;
23 | }
24 |
25 | public static function parse($digest = NULL)
26 | {
27 | // mod_php
28 | if(isset($_SERVER['PHP_AUTH_USER']) AND isset($_SERVER['PHP_AUTH_PW']))
29 | {
30 | $data = array('client_id' => $_SERVER['PHP_AUTH_USER'], 'client_secret' => $_SERVER['PHP_AUTH_PW']);
31 | }
32 | // most other servers
33 | elseif (isset($_SERVER['HTTP_AUTHORIZATION'])
34 | AND strpos(strtolower($_SERVER['HTTP_AUTHORIZATION']), 'basic') === 0)
35 | {
36 | $params = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)), 2);
37 |
38 | $data = array('client_id' => $params[0], 'client_secret' => $params[1]);
39 | }
40 |
41 | return empty($data) ? FALSE : $data;
42 | }
43 |
44 | } // END Oauthz_Token_Basic
45 |
--------------------------------------------------------------------------------
/classes/controller/client.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Client_Controller
11 | * *
12 | */
13 | class Controller_Client extends Oauthz_Client {
14 |
15 | public function action_index()
16 | {
17 | $template = new View('oauthz-template');
18 |
19 | $template->content = new View('oauthz-client');
20 |
21 | $this->request->response = $template->render();
22 | }
23 |
24 | public function action_test()
25 | {
26 | try
27 | {
28 | $resource = Remote::get('http://docs/api/get/1',array(
29 | CURLOPT_POST => TRUE,
30 | CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded;charset=UTF-8'),
31 | CURLOPT_POSTFIELDS => http_build_query(array(
32 | 'client_id' => 'OA_4bfbc43769917',
33 | //'oauth_token' => $token->access_token,
34 | //'refresh_token' => $token->refresh_token,
35 | //'expires_in' => $token->expires_in
36 | ), '', '&')
37 | ));
38 | }
39 | catch (Exception $e)
40 | {
41 | $resource = $e->getMessage();
42 | }
43 | echo ''.print_r($resource,TRUE).' ';
44 | }
45 |
46 | } // END Controller Consumer
47 |
--------------------------------------------------------------------------------
/config/oauth-api.php:
--------------------------------------------------------------------------------
1 | array(
10 |
11 | 'formats' => array(
12 | 'json' => FALSE, // 'application/json'
13 | 'xml' => FALSE, // 'application/xml'
14 | 'form' => FALSE, // 'text/plain'
15 | 'html' => FALSE, // 'text/html'
16 | 'csv' => FALSE, // 'application/csv'
17 | 'php' => FALSE, // 'text/plain'
18 | 'serialize' => FALSE // 'application/vnd.php.serialized'
19 | ),
20 |
21 | 'methods' => array(
22 | 'HEAD' => TRUE,
23 | 'GET' => TRUE,
24 | 'POST' => TRUE,
25 | 'PUT' => TRUE,
26 | 'DELETE' => TRUE
27 | ),
28 |
29 | /**
30 | * Parameters should be required when access protected resource
31 | * cryptographic token or bear token
32 | */
33 | 'bearer' => array(
34 | 'access_token' => TRUE,
35 | 'scope' => FALSE
36 | ),
37 |
38 | 'mac' => array(
39 | 'access_token' => TRUE,
40 | 'mac_key' => TRUE,
41 | 'mac_algorithm' => TRUE,
42 | 'scope' => FALSE
43 | ),
44 |
45 | 'max_requests' => array(
46 | 500, // common client
47 | 1000, // first class client
48 | 1500 // vip client
49 | )
50 |
51 | )
52 |
53 | ); // END OAuth API config
54 |
--------------------------------------------------------------------------------
/classes/controller/api.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Api
11 | * *
12 | */
13 | class Controller_Api extends Oauthz_Api {
14 |
15 | protected $_exclude = array('xrds', 'index');
16 |
17 | /**
18 | * Accessing Protected Resources
19 | *
20 | * @access public
21 | * @return void
22 | */
23 | public function action_index()
24 | {
25 | $methods = array();
26 | foreach(get_class_methods($this) as $method)
27 | {
28 | if(substr($method, 0, 7) === 'action_')
29 | {
30 | $method = ltrim($method, 'action_');
31 | $methods[$method] = url::site('/api/'.$method, TRUE);
32 | }
33 | }
34 | $this->request->response = str_replace('\\/', '/', json_encode($methods));
35 | }
36 |
37 | public function action_get($id = NULL)
38 | {
39 | $data = array(
40 | array('Humm', 'Hah'),
41 | array('Zzz', 'Yaaa'),
42 | array('Giii', 'Neee')
43 | );
44 | $this->request->response = json_encode(isset($data[$id]) ? $data[$id] : array('Hello OAuth 2.0, when you see this info, it means you successfully access protected resources',));
45 | }
46 |
47 | public function action_create()
48 | {
49 | //
50 | }
51 |
52 | public function action_update()
53 | {
54 | //
55 | }
56 |
57 | public function action_delete()
58 | {
59 | //
60 | }
61 |
62 | } // END Controller_Api
63 |
--------------------------------------------------------------------------------
/guide/oauthz/demo.md:
--------------------------------------------------------------------------------
1 | # Understand the demo step by step
2 |
3 | Note: before runing these steps, you have to setup the OAuth server. see README
4 |
5 | ### Getting the client ID from OAuth server ###
6 |
7 | + Access `http://example.com/oauth/index`
8 | + Login by an valid email address. e.g. `demo@example.com`
9 | + Register a client ID in the server page. e.g. `client_id: OAL_4D2ACB5280EF8, client_secrect: demo`
10 |
11 | ### Setting client connection settings ###
12 |
13 | 1. Request URIs options,
14 |
15 | 'oauth-uri' => 'http://example.com/oauth/code', // the uri for requesting authorization_code
16 | 'token-uri' => 'http://example.com/oauth/token', // the uri for requesting access_token
17 | 'api-uri' => 'http://example.com/api/', // the uri for requesting protected resource
18 | 'redirect_uri' => 'http://my-web-server.com/client/do' // the uri holded by yourself
19 |
20 | 2. Config the OAuth client ID and secrect `config/oauth-client.php` with the `client_id` and `client_secrect` above.
21 | 3. Note: Other options is for future, they are still in clound and waiting for implement.
22 |
23 | ### Go on, thinking you are the smart user and try to experiement the stupid service ###
24 |
25 | + Access `http://my-web-server.com/client/index`
26 | + the script in your web site now is connecting to `http://example.com/oauth/code` to get an `authorization_code`.
27 | this works in background and can NOT feel,even you are smart
28 | + What you see is `http://example.com/oauth/code?response_type=code&client_id=OA_4bfbc43769917&redirect_uri=http%3A%2F%2Fmy-web-server.com%2Fclient%2Fdo`
29 | + To approve or not to? approve will grant my-web-server.com steal some protected information, which owned by you in example.com.
30 | No? okay that is it.
31 |
32 | ### How these work? ###
33 | Hmm, I have no more time to complete this answer at this moment. help me please.
34 |
--------------------------------------------------------------------------------
/classes/oauthz/authentication.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | abstract class Oauthz_Authentication {
13 |
14 | protected $_client_id;
15 |
16 | protected $_token;
17 |
18 | public static function factory($token_type, array $config, array $params)
19 | {
20 | $token_type = 'Oauthz_Token_'.$token_type;
21 |
22 | $oauth = new $token_type;
23 |
24 | foreach($config as $key => $val)
25 | {
26 | if($val === TRUE)
27 | {
28 | if(isset($params[$key]) AND $value = rawurldecode($params[$key]))
29 | {
30 | $oauth->$key = $value;
31 | }
32 | else
33 | {
34 | throw new Oauthz_Exception_Access('invalid_grant', self::state($params));
35 | }
36 | }
37 | elseif($val !== FALSE)
38 | {
39 | $oauth->$key = $val;
40 | }
41 | }
42 |
43 | return $oauth;
44 | }
45 |
46 | public function client_id()
47 | {
48 | return $this->_client_id;
49 | }
50 |
51 | public function token()
52 | {
53 | return $this->access_token;
54 | }
55 |
56 | public static function state($params)
57 | {
58 | // Parse the "state" paramter
59 | if(isset($params['state']) AND ($state = rawurldecode($params['state'])))
60 | {
61 | $param = array('state' => $state);
62 | }
63 | else
64 | {
65 | $param = NULL;
66 | }
67 |
68 | return $param;
69 | }
70 |
71 | abstract public function verify($token);
72 |
73 | } // END Oauthz_Authentication
74 |
--------------------------------------------------------------------------------
/classes/oauthz/core.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | abstract class Oauthz_Core {
13 |
14 | const VERSION = '0.22-eva';
15 |
16 | /**
17 | * OAuth server configuration group name
18 | *
19 | * @access protected
20 | * @var string $_type
21 | */
22 | public static $type = 'default';
23 |
24 | public static function config($key = NULL, $type = NULL)
25 | {
26 | static $config;
27 |
28 | isset($type) OR $type = Oauthz::$type;
29 |
30 | if( ! isset($config[$type]))
31 | {
32 | if( ! $config[$type] = Kohana::config('oauth-server')->get($type))
33 | {
34 | throw new Kohana_Exception('There is no ":group" in your config file oauth-server.php'
35 | , array(':group' => $type));
36 | }
37 | }
38 |
39 | return isset($key) ? isset($config[$type][$key]) ? $config[$type][$key] : NULL : $config[$type];
40 | }
41 |
42 | /**
43 | * Oauthz_Signature::factory alias
44 | *
45 | * @access public
46 | * @param string $method
47 | * @param string $identifier
48 | * @return object
49 | * @see Oauthz_Signature::factory
50 | */
51 | public static function signature($method, $identifier)
52 | {
53 | return Oauthz_Signature::factory($method, $identifier);
54 | }
55 |
56 | public static function grant_access_uri($redirect)
57 | {
58 | return $redirect.URL::query();
59 | }
60 |
61 | public static function access_denied_uri($redirect = NULL)
62 | {
63 | if( ! $redirect) $redirect = Arr::get($_GET, 'redirect_uri');
64 | if( $state = Arr::get($_GET, 'state')) $state = '&state='.$state;
65 | return $redirect.'?error=access_denied'.$state;
66 | }
67 |
68 | } // END Oauthz Core
69 |
--------------------------------------------------------------------------------
/classes/oauthz/server.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Kohana_Controller
11 | * *
12 | */
13 | class Oauthz_Server extends Kohana_Controller {
14 |
15 | protected $template = 'oauthz-template';
16 |
17 | public function before()
18 | {
19 | $this->template = new View($this->template);
20 | }
21 |
22 | public function action_register($client_id = NULL)
23 | {
24 | $data = array();
25 | $client = new Model_Oauthz_Client;
26 | if($client_id)
27 | {
28 | $data = (array) $client->get($client_id, $_SESSION['user']['uid']);
29 | }
30 | elseif(isset($_POST['__v_state__']))
31 | {
32 | $_POST['user_id'] = $_SESSION['user']['uid'];
33 |
34 | $valid = empty($_POST['server_id']) ? $client->append($_POST) : $client->update($_POST['server_id'], $_POST);
35 |
36 | if($valid instanceOf Validate)
37 | {
38 | $data = $valid->as_array();
39 | $data['errors'] = $valid->errors('validate');
40 | }
41 | else
42 | {
43 | $data += $valid;
44 | }
45 | }
46 |
47 | $this->template->content = new View('oauthz-server-register', $data);
48 |
49 | $this->request->response = $this->template->render();
50 | }
51 |
52 | public function action_client()
53 | {
54 | $client = new Model_Oauthz_Client;
55 |
56 | $data = $client->lists(array('user_id' => $_SESSION['user']['uid']));
57 |
58 | $this->template->content = new View('oauthz-server-client', $data);
59 |
60 | $this->request->response = $this->template->render();
61 | }
62 |
63 | public function action_access_deny()
64 | {
65 | $this->request->status = 302; #HTTP/1.1 302 Found
66 | $this->request->headers['Content-Type'] = 'application/x-www-form-urlencoded';
67 | $this->request->headers['Location'] = 'http://example.com/rd#error=user_denied';
68 | }
69 |
70 | } // END Oauthz_Server
71 |
--------------------------------------------------------------------------------
/config/oauth-client.php:
--------------------------------------------------------------------------------
1 | array(
8 | // uri to obtain authorization code
9 | 'oauth-uri' => 'http://docs/oauth/code',
10 |
11 | // uri to obtain the access token
12 | 'token-uri' => 'http://docs/oauth/token',
13 |
14 | // Restful web service api base url
15 | 'api-uri' => 'http://docs/api/',
16 |
17 | // Must be code, token, password, client_credentials
18 | 'protocol-flow' => 'code',
19 |
20 | // Parameters for Authorization Code flow
21 | 'code' => array(
22 | 'client_id' => 'OAL@4EED687F28A72',
23 | 'client_secret' => '000000',
24 | 'token_type' => 'bearer', // bearer, hmac-sha1, rsa-sha1, md5
25 | 'scope' => '',
26 | 'state' => 'test',
27 | 'redirect_uri' => 'http://docs/client/do'
28 | ),
29 | // Parameters for Implicit Grant Flow
30 | 'token' => array(
31 | 'client_id' => 'OAL_4D2EA62621E4F',
32 | 'client_secret' => 'sss',
33 | 'token_type' => 'BEARER', // BEARER, HMAC-SHA1, RSA-SHA1, MD5
34 | 'scope' => '',
35 | 'state' => '',
36 | 'redirect_uri' => 'http://docs/client/do'
37 | ),
38 | // Parameters for Resource Owner Password Credentials Flow
39 | 'password' => array(
40 | 'username' => 'OAL_4D2EA62621E4F',
41 | 'password' => 'sss',
42 | 'client_id' => 'OAL_4D2EA62621E4F',
43 | 'client_secret' => 'sss',
44 | 'token_type' => 'BEARER', // BEARER, HMAC-SHA1, RSA-SHA1, MD5
45 | 'scope' => '',
46 | 'state' => '',
47 | ),
48 | // Parameters for Client Credentials Flow
49 | 'client_credentials' => array(
50 | 'client_id' => 'OAL_4D2EA62621E4F',
51 | 'client_secret' => 'sss',
52 | 'token_type' => 'BEARER', // BEARER, HMAC-SHA1, RSA-SHA1, MD5
53 | 'scope' => '',
54 | 'state' => '',
55 | )
56 | ),
57 |
58 | ); // END OAuth client config
59 |
--------------------------------------------------------------------------------
/views/oauthz-server-error.php:
--------------------------------------------------------------------------------
1 | param('id'))
3 | $uri = Request::$current->controller.'/'.Request::$current->action.'/';
4 | else
5 | $uri = Request::$current->uri.'/';
6 | ?>Service error codes description
7 | Request Stage Error Code Description URI
8 | ';
12 | $count = count($code_errors);
13 | foreach($code_errors as $error_code => $error_info)
14 | {
15 | ?>'.__('Authorization Response').'';
18 | $count = FALSE;
19 | }
20 | ?>/ ';
25 | }
26 |
27 | if(isset($token_errors))
28 | {
29 | echo '';
30 | $count = count($token_errors);
31 | foreach($token_errors as $error_code => $error_info)
32 | {
33 | ?>'.__('Access Token Response').'';
36 | $count = FALSE;
37 | }
38 | ?>/ ';
43 | }
44 |
45 | if(isset($access_errors))
46 | {
47 | echo ' ';
48 | $count = count($access_errors);
49 | foreach($access_errors as $error_code => $error_info)
50 | {
51 | ?>'.__('Access Protected Resource').'';
54 | $count = FALSE;
55 | }
56 | ?>/ ';
61 | }
62 | ?>
--------------------------------------------------------------------------------
/classes/oauthz/token/mac.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Authentication
11 | * *
12 | */
13 | class Oauthz_Token_Mac extends Oauthz_Authentication {
14 |
15 | public function verfiy($token)
16 | {
17 | // Pull the public key ID from the certificate
18 | $public_key = openssl_get_publickey($token->public_cert);
19 |
20 | // Check the computed signature against the one passed in the query
21 | $data = openssl_verify($this->identifier, base64_decode($this->signature), $public_key);
22 |
23 | // Release the key resource
24 | openssl_free_key($public_key);
25 |
26 | return $data === 1;
27 | }
28 |
29 | // function to parse the http auth header
30 | public static function parse($digest = NULL)
31 | {
32 | $info = FALSE;
33 |
34 | return $info;
35 | }
36 |
37 | public function rsa_sha1($token)
38 | {
39 | // Pull the private key ID from the certificate
40 | $private_key = openssl_get_privatekey($token->private_cert);
41 |
42 | // Sign using the key
43 | if(openssl_sign($this->identifier, $this->signature, $private_key) !== TRUE)
44 | {
45 | throw new Oauthy_Exception('');
46 | }
47 |
48 | // Release the key resource
49 | openssl_free_key($private_key);
50 |
51 | return base64_encode($this->signature);
52 | }
53 |
54 | public function hmac_sha1($token)
55 | {
56 | $key = rawurlencode($token->client_secret);
57 |
58 | if( ! empty($token->token_secret))
59 | {
60 | $key .= '&'.rawurlencode($token->token_secret);
61 | }
62 |
63 | return $this->signature === base64_encode(hash_hmac('sha1', $this->identifier, $key, TRUE));
64 | }
65 |
66 | /**
67 | * Normalized request string for signature verify
68 | *
69 | * @access public
70 | * @param string $method
71 | * @param string $uri
72 | * @param array $params
73 | * @return string
74 | */
75 | public static function identifier($method, $uri, array $params)
76 | {
77 | // The signature parameter MUST be excluded.
78 | unset($params['signature']);
79 |
80 | return $method.'&'.rawurlencode($uri).'&'.http_build_query($params, '', '&');
81 | }
82 |
83 | } // END Oauthz_Token_Mac
84 |
--------------------------------------------------------------------------------
/classes/oauthz/token/digest.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2011 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Authentication
11 | * *
12 | */
13 | class Oauthz_Token_Digest extends Oauthz_Authentication {
14 |
15 | public function verfiy($token)
16 | {
17 | if($data = static::parse() AND $data['username'] === $token['client_id'])
18 | {
19 | // generate the valid response
20 | $realm = md5("$token['client_id']:$data['realm']:$token['client_secret']");
21 | $method = md5("$_SERVER['REQUEST_METHOD']:$data['uri']");
22 |
23 | $data = $data['response'] === md5("$realm:$data['nonce']:$data['nc']:$data['cnonce']:$data['qop']:$method");
24 | }
25 |
26 | return $data;
27 | }
28 |
29 | // function to parse the http auth header
30 | public static function parse($digest = NULL)
31 | {
32 | if($digest === NULL)
33 | {
34 | // mod_php
35 | if (isset($_SERVER['PHP_AUTH_DIGEST']))
36 | {
37 | $digest = $_SERVER['PHP_AUTH_DIGEST'];
38 | }
39 | // most other servers
40 | elseif (isset($_SERVER['HTTP_AUTHORIZATION'])
41 | AND strpos(strtolower($_SERVER['HTTP_AUTHORIZATION']), 'digest') === 0)
42 | {
43 | $digest = substr($_SERVER['HTTP_AUTHORIZATION'], 7);
44 | }
45 | }
46 |
47 | $info = FALSE;
48 |
49 | if($digest)
50 | {
51 | // protect against missing data
52 | $fields = array(
53 | 'nonce' => 1,
54 | 'nc' => 1,
55 | 'cnonce' => 1,
56 | 'qop' => 1,
57 | 'username' => 1,
58 | 'uri' => 1,
59 | 'response' => 1,
60 | 'realm' => 1
61 | );
62 |
63 | preg_match_all('@('.implode('|', array_keys($fields)).')=[\'"]?([^\'",]+)@', $digest, $matches, PREG_SET_ORDER);
64 |
65 | $data = array();
66 |
67 | foreach($matches as $match)
68 | {
69 | $data[$match[1]] = $match[2] ? $match[2] : ($match[3] ?: $match[4]);
70 | unset($fields[$match[1]]);
71 | }
72 |
73 | empty($fields) AND $info = $data;
74 | }
75 |
76 | return $info;
77 | }
78 |
79 | } // END Oauthz_Token_Digest
80 |
--------------------------------------------------------------------------------
/views/oauthz-server-register.php:
--------------------------------------------------------------------------------
1 |
2 |
47 |
48 | Note: ☺, This should be generated from system and updated regularly in some days
49 | ☺☺, MAY include an application/x-www-form-urlencoded formatted query component, but fragment component is not allowed
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Kohana OAuth 2 Module #
2 |
3 | #OAuth protocal v2 [draft 22](http://tools.ietf.org/wg/oauth/)
4 |
5 | ### Requirement ###
6 | 1) php v5.2+, curl extension to run the demo
7 |
8 | 2) MySQL, SQLite, MSSQL or NOSQL database
9 |
10 | 3) Kohana [v3.0.x](http://dev.kohanaframework.org/attachments/download/1649/kohana-3.0.10.zip), I have no plan to support v3.1+ ATM
11 |
12 | 4) Apache, Nignx, a web server
13 |
14 | ## Server ##
15 |
16 | ### Install and configuration ###
17 |
18 | 1) Create the oauth data tabe by execute `oauth.sql` in doc directory
19 |
20 | 2) Configurate the server parameters in `config/oauthz-server.php`
21 |
22 | ### Modify interface show to users ###
23 |
24 | 1) Client have to register an account before they access the protected resources. they can also manage their account
25 |
26 | 2) Resource owners personal information management.
27 |
28 | ``` php
29 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Controller
11 | * *
12 | */
13 | class Controller_Oauth extends Oauthz_Controller {
14 |
15 | public function action_index()
16 | {
17 | $template = new View('oauthz-template');
18 | $template->content = 'Hello guest. ';
19 | $this->request->response = $template;
20 | }
21 |
22 | public function action_code()
23 | {
24 | $query = URL::query();
25 | $template = new View('oauthz-template');
26 | $view = new View('oauthz-server-authorize', array('authorized' => TRUE, 'query' => $query));
27 | $template->content = $view->render();
28 | $this->request->response = $template;
29 | }
30 |
31 | public function action_error($error_code = NULL)
32 | {
33 | $error = array();
34 |
35 | $errors['code_errors'] = I18n::get('Authorization Errors Response');
36 | $errors['token_errors'] = I18n::get('Token Errors Response');
37 | $errors['access_errors'] = I18n::get('Access Errors Response');
38 |
39 | if(isset($errors['code_errors'][$error_code]))
40 | {
41 | $error['code_errors'][$error_code] = $errors['code_errors'][$error_code];
42 | }
43 |
44 | if(isset($errors['token_errors'][$error_code]))
45 | {
46 | $error['token_errors'][$error_code] = $errors['code_errors'][$error_code];
47 | }
48 |
49 | if(isset($errors['access_errors'][$error_code]))
50 | {
51 | $error['access_errors'][$error_code] = $errors['code_errors'][$error_code];
52 | }
53 |
54 | if($error)
55 | {
56 | $error['error_code'] = $error_code;
57 | $errors = $error;
58 | }
59 |
60 | $template = new View('oauthz-template');
61 | $view = new View('oauthz-server-error', $errors);
62 | $template->content = $view->render();
63 | $this->request->response = $template;
64 | }
65 |
66 | public function action_signin()
67 | {
68 | if( ! empty($_POST['usermail']) AND Validate::email($_POST['usermail']))
69 | {
70 | $user = array(
71 | 'uid' => $_SERVER['REQUEST_TIME'],
72 | 'mail' => $_POST['usermail']
73 | );
74 | Cookie::set('user', json_encode($user));
75 | Session::instance()->set('user', $user);
76 | $this->request->redirect(arr::get($_GET, 'redirect', 'server/index'));
77 | }
78 | elseif($user = Oauthz::is_login())
79 | {
80 | Session::instance()->set('user', json_decode($user, TRUE));
81 | $this->request->redirect(arr::get($_GET, 'redirect', 'server/index'));
82 | }
83 |
84 | $template = new View('oauthz-template');
85 | $view = new View('oauthz-server-signin');
86 | $template->content = $view->render();
87 | $this->request->response = $template;
88 | }
89 |
90 | public function action_logout()
91 | {
92 | Cookie::delete('user');
93 | Session::instance()->delete('user');
94 | $this->request->redirect('oauth/index');
95 | }
96 |
97 | public function action_okay()
98 | {
99 | echo $this->request->referrer;
100 | }
101 |
102 | } // END Controller Consumer
103 |
--------------------------------------------------------------------------------
/i18n/en.php:
--------------------------------------------------------------------------------
1 | 'Authorization Response',
5 | 'Access Token Response' => 'Access Token Response',
6 | 'Access Protected Resource' => 'Access Protected Resource',
7 |
8 | // Error Response
9 | 'Authorization Errors Response' => array(
10 | 'invalid_request' => 'The request is missing a required parameter, includes an
11 | unsupported parameter or parameter value, or is otherwise malformed.',
12 |
13 | 'unauthorized_client' => 'The client is not authorized to request an authorization
14 | code using this method.',
15 |
16 | 'access_denied' => 'The resource owner or authorization server denied the request.',
17 |
18 | 'unsupported_response_type' => 'The authorization server does not support obtaining an
19 | authorization code using this method.',
20 |
21 | 'invalid_scope' => 'The requested scope is invalid, unknown, or malformed.',
22 |
23 | 'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.',
24 |
25 | 'temporarily_unavailable'=> 'The authorization server is currently unable to handle the
26 | request due to a temporary overloading or maintenance of the server.'
27 | ),
28 | // Error Response
29 | 'Token Errors Response' => array(
30 | 'invalid_request' => 'The request is missing a required parameter, includes an
31 | unsupported parameter or parameter value, or is otherwise malformed.',
32 |
33 | 'unauthorized_client' => 'The client is not authorized to request an access token using this method.',
34 |
35 | 'access_denied' => 'The resource owner or authorization server denied the request.',
36 |
37 | 'unsupported_response_type' => 'The authorization server does not support obtaining an access token using this method.',
38 |
39 | 'invalid_scope' => 'The requested scope is invalid, unknown, or malformed.',
40 |
41 | 'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.',
42 |
43 | 'temporarily_unavailable'=> 'The authorization server is currently unable to handle the
44 | request due to a temporary overloading or maintenance of the server.'
45 | ),
46 | // Error Response
47 | 'Access Errors Response' => array(
48 | 'invalid_request' => 'The request is missing a required parameter, includes an
49 | unsupported parameter or parameter value, repeats a
50 | parameter, includes multiple credentials, utilizes more
51 | than one mechanism for authenticating the client, or is
52 | otherwise malformed.',
53 |
54 | 'invalid_client' => 'Client authentication failed (e.g. unknown client, no
55 | client credentials included, multiple client credentials
56 | included, or unsupported credentials type).',
57 |
58 | 'invalid_grant' => 'The provided authorization grant is invalid, expired,
59 | revoked, or does not match the redirection URI used in
60 | the authorization request.',
61 |
62 | 'unauthorized_client' => 'The authenticated client is not authorized to use this
63 | authorization grant type.',
64 |
65 | 'unsupported_grant_type'=> 'The authorization grant type is not supported by the
66 | authorization server.',
67 |
68 | 'invalid_scope' => 'The requested scope is invalid, unknown, malformed, or
69 | exceeds the previously granted scope.'
70 | )
71 |
72 | );
73 |
--------------------------------------------------------------------------------
/classes/oauthz/exception.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | class Oauthz_Exception extends Exception {
13 |
14 | /**
15 | * REQUIRED. A single error code
16 | *
17 | * @access public
18 | * @var string $error
19 | */
20 | public $error;
21 |
22 | /**
23 | * OPTIONAL. A human-readable text providing additional information,
24 | * used to assist in the understanding and resolution of the error occurred.
25 | *
26 | * @access public
27 | * @var string $error_description
28 | */
29 | public $error_description;
30 |
31 | /**
32 | * OPTIONAL. A URI identifying a human-readable web page with
33 | * information about the error, used to provide the resource owner
34 | * with additional information about the error.
35 | *
36 | * @access public
37 | * @var string $error_uri
38 | */
39 | protected $error_uri;
40 |
41 | /**
42 | * Initial OAuth error codes from config settings
43 | *
44 | * @access public
45 | * @param string $message
46 | * @param string $state extras parameters
47 | * @param string $code default [ 0 ]
48 | * @return void
49 | */
50 | public function __construct($message, array $state = NULL, $code = 0)
51 | {
52 | $this->error = $message;
53 | $this->state = array_filter((array) $state);
54 |
55 | // Pass the message to the parent
56 | parent::__construct($message, $code);
57 | }
58 |
59 | public function as_json()
60 | {
61 | $state = $this->state;
62 |
63 | $params = array('error' => $this->error);
64 |
65 | if(isset($state['error_uri']))
66 | {
67 | $params['error_uri'] = url::site($state['error_uri'], TRUE);
68 |
69 | // don't append the customize error_uri to querystring
70 | unset($state['error_uri']);
71 | }
72 | else
73 | {
74 | $params['error_uri'] = url::site(Oauthz::config('error_uri'), TRUE).'/'.$this->error;
75 | }
76 |
77 | if(isset($state['error_description']))
78 | {
79 | $params['error_description'] = __($state['error_description']);
80 |
81 | // don't append the customize error_description to querystring
82 | unset($state['error_description']);
83 | }
84 | else
85 | {
86 | $params['error_description'] = $this->error_description;
87 | }
88 |
89 | empty($state) OR $params['error_uri'] .= '?'.http_build_query($state, '', '&');
90 |
91 | // JSON_UNESCAPED_SLASHES
92 | return str_replace('\\/', '/', json_encode($params));
93 | }
94 |
95 | public function as_query()
96 | {
97 | if(isset($this->state['error_uri']))
98 | {
99 | $params = array('error' => $this->error) + $this->state;
100 |
101 | if(isset($params['error_description']))
102 | {
103 | $params['error_description'] = __($params['error_description']);
104 | }
105 | else
106 | {
107 | $params['error_description'] = $this->error_description;
108 | }
109 |
110 | $error_uri = url::site($params['error_uri'], TRUE);
111 |
112 | // don't append error_uri to querystring
113 | unset($params['error_uri']);
114 |
115 | $error_uri .= '?'.http_build_query($params, '', '&');
116 | }
117 | else
118 | {
119 | // no need to expose error, error_description
120 | $error_uri = url::site(Oauthz::config('error_uri'), TRUE).'/'.$this->error;
121 |
122 | empty($this->state) OR $error_uri .= '?'.http_build_query($this->state, '', '&');
123 | }
124 |
125 | return $error_uri;
126 | }
127 |
128 | } // END OAuth_Exception
129 |
--------------------------------------------------------------------------------
/classes/oauthz/extension/code.php:
--------------------------------------------------------------------------------
1 |
8 | * @package Oauthz
9 | * @copyright (c) 2010 OALite
10 | * @license ISC License (ISCL)
11 | * @link http://oalite.com
12 | * @see Oauthz_Extension
13 | * *
14 | */
15 | class Oauthz_Extension_Code extends Oauthz_Extension {
16 |
17 | /**
18 | * REQUIRED. The client identifier as described in Section 2.1.
19 | *
20 | * @access public
21 | * @var string $client_id
22 | */
23 | public $client_id;
24 |
25 | /**
26 | * REQUIRED. The redirection URI used in the initial request.
27 | *
28 | * @access public
29 | * @var string $redirect_uri
30 | */
31 | public $redirect_uri;
32 |
33 | public $expires_in;
34 |
35 | /**
36 | * Load oauth parameters from GET or POST
37 | *
38 | * @access public
39 | * @param string $flag default [ FALSE ]
40 | * @return void
41 | * @throw Oauthz_Exception_Authorize Error Codes: invalid_request
42 | */
43 | public function __construct(array $args)
44 | {
45 | // Parse the "state" paramter
46 | if(isset($_GET['state']))
47 | {
48 | $this->state['state'] = rawurldecode($_GET['state']);
49 |
50 | unset($args['state']);
51 | }
52 |
53 | // Check all required parameters should not be empty
54 | foreach($args as $key => $val)
55 | {
56 | if($val === TRUE)
57 | {
58 | if(isset($_GET[$key]) AND $value = rawurldecode($_GET[$key]))
59 | {
60 | $this->$key = $value;
61 | }
62 | else
63 | {
64 | throw new Oauthz_Exception_Authorize('invalid_request', $this->state);
65 | }
66 | }
67 | elseif($val !== FALSE)
68 | {
69 | $this->$key = $val;
70 | }
71 | }
72 | }
73 |
74 | /**
75 | * Populate the oauth token from the request info and client info store in the server
76 | *
77 | * @access public
78 | * @param array $client
79 | * @return Oauthz_Token
80 | * @throw Oauthz_Exception_Authorize Error Codes: invalid_scope, unauthorized_client
81 | */
82 | public function execute()
83 | {
84 | // Verify the client and generate a code if successes
85 | if($client = Model_Oauthz::factory('Token')
86 | ->code($this->client_id, $this->token_type, $this->expires_in))
87 | {
88 | // audit
89 | }
90 | else
91 | {
92 | // Invalid client_id
93 | throw new Oauthz_Exception_Authorize('unauthorized_client', $this->state);
94 | }
95 |
96 | if($client['redirect_uri'] !== $this->redirect_uri)
97 | {
98 | throw new Oauthz_Exception_Authorize('unauthorized_client', $this->state);
99 | }
100 |
101 | if( ! empty($this->scope) AND ! empty($client['scope']))
102 | {
103 | if( ! in_array($this->scope, explode(' ', $client['scope'])))
104 | {
105 | // Redirect to client uri
106 | $params = $this->state;
107 | $params['error_uri'] = $this->redirect_uri;
108 |
109 | throw new Oauthz_Exception_Authorize('invalid_scope', $params);
110 | }
111 | }
112 |
113 | // Grants Authorization
114 | $token = new Oauthz_Token;
115 |
116 | $token->code = $client['code'];
117 | $token->token_type = $client['token_type'];
118 | $token->expires_in = $client['expires_in'];
119 |
120 | isset($this->state['state']) AND $token->state = $this->state['state'];
121 |
122 | return $this->redirect_uri.'?'.$token->as_query();
123 | }
124 |
125 | } // END Oauthz_Extension_Code
126 |
--------------------------------------------------------------------------------
/classes/oauthz/extension/assertion.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Oauthz_Extension
11 | * *
12 | */
13 | class Oauthz_Extension_Assertion extends Oauthz_Extension {
14 |
15 | /**
16 | * assertion_type
17 | * REQUIRED. The format of the assertion as defined by the
18 | * authorization server. The value MUST be an absolute URI.
19 | */
20 | public $assertion_type;
21 |
22 | /**
23 | * assertion
24 | * REQUIRED. The assertion.
25 | */
26 | public $assertion;
27 |
28 | /**
29 | * client_id
30 | * OPTIONAL. The client identifier as described in Section 2.1.
31 | * The authorization server MAY require including the client
32 | * credentials with the request based on the assertion properties.
33 | * client_secret
34 | * OPTIONAL. The client secret as described in Section 2.1. MUST
35 | * NOT be included if the "client_id" parameter is omitted.
36 | * scope
37 | * OPTIONAL. The scope of the access request expressed as a list
38 | * of space-delimited strings. The value of the "scope" parameter
39 | * is defined by the authorization server. If the value contains
40 | * multiple space-delimited strings, their order does not matter,
41 | * and each string adds an additional access range to the
42 | * requested scope.
43 | * format
44 | * OPTIONAL. The response format requested by the client. Value
45 | * MUST be one of "json", "xml", or "form". Alternatively, the
46 | * client MAY use the HTTP "Accept" header field with the desired
47 | * media type. Defaults to "json" if omitted and no "Accept"
48 | * header field is present.
49 | */
50 |
51 | public function __construct($args = NULL)
52 | {
53 | $params = Oauthz::parse_query();
54 | $this->assertion_type = Arr::get($params, 'username');
55 | $this->assertion = Arr::get($params, 'password');
56 |
57 | if(NULL !== $client_id = Arr::get($params, 'client_id'))
58 | $this->client_id = $client_id;
59 |
60 | if(NULL !== $client_secret = Arr::get($params, 'client_secret'))
61 | $this->client_secret = $client_secret;
62 |
63 | if(NULL !== $scope = Arr::get($params, 'scope'))
64 | $this->scope = $scope;
65 |
66 | if(NULL !== $format = Arr::get($params, 'format'))
67 | $this->format = $format;
68 | }
69 |
70 | public function execute()
71 | {
72 | $token = new Model_Oauthz_Token;
73 |
74 | if( ! $client = $token->assertion($this->client_id))
75 | {
76 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
77 | }
78 |
79 | if($client['assertion_type'] !== $this->assertion_type)
80 | {
81 | throw new Oauthz_Exception_Token('unknown-format', $this->state);
82 | }
83 |
84 | if($client['assertion'] !== $this->assertion
85 | OR (property_exists($this, 'client_id') AND $client['client_id'] !== $this->client_id)
86 | OR (property_exists($this, 'client_secret') AND $client['client_secret'] !== sha1($this->client_secret))
87 | OR (property_exists($this, 'scope') AND ! isset($client['scope'][$this->scope]))
88 | {
89 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
90 | }
91 |
92 | $token = new Oauthz_Token;
93 |
94 | // Grants Authorization
95 | // The authorization server SHOULD NOT issue a refresh token.
96 | $token->access_token = $client['access_token'];
97 | $token->assertion_type = $this->assertion_type;
98 |
99 | return $token;
100 | }
101 |
102 | } // END Oauthz_Extension_Assertion
103 |
--------------------------------------------------------------------------------
/classes/oauthz/controller.php:
--------------------------------------------------------------------------------
1 |
7 | * @package Oauthz
8 | * @copyright (c) 2010 OALite
9 | * @license ISC License (ISCL)
10 | * @link http://oalite.com
11 | * @see Kohana_Controller
12 | * *
13 | */
14 | abstract class Oauthz_Controller extends Kohana_Controller {
15 |
16 | /**
17 | * The end-user authenticates directly with the authorization server, and grants client access to its protected resources
18 | *
19 | * @access public
20 | * @return void
21 | */
22 | public function action_authorize()
23 | {
24 | try
25 | {
26 | // There is handler for this response type
27 | if($response_type = Arr::get($_GET, 'response_type'))
28 | {
29 | $arguments = Arr::get(Oauthz::config('params'), $response_type, array());
30 |
31 | if($extension = Oauthz_Extension::factory($response_type, $arguments))
32 | {
33 | if( ! Oauthz::is_login())
34 | {
35 | $this->request->redirect(Oauthz::config('login_uri').'redirect='.rawurlencode($this->request->url().url::query()));
36 | }
37 | $response = $extension->execute();
38 | }
39 | }
40 |
41 | // This response type is unsupported
42 | if( ! isset($response))
43 | {
44 | $params = isset($_GET['state']) ? array('state' => $_GET['state']) : NULL;
45 |
46 | throw new Oauthz_Exception_Authorize('unsupported_response_type', $params);
47 | }
48 | }
49 | catch (Oauthz_Exception $e)
50 | {
51 | $response = $e->as_query();
52 | }
53 |
54 | // HTTP/1.1 302 Found
55 | $this->request->status = 302;
56 | $this->request->headers['Content-Type'] = 'application/x-www-form-urlencoded';
57 | $this->request->redirect($response);
58 | }
59 |
60 | /**
61 | * Access token handler for the client requests
62 | *
63 | * @access public
64 | * @return void
65 | */
66 | public function action_token()
67 | {
68 | try
69 | {
70 | // There is handler for this grant type
71 | if($grant_type = Oauthz::get('grant_type'))
72 | {
73 | $arguments = Arr::get(Oauthz::config('params'), $grant_type, array());
74 |
75 | if($extension = Oauthz_Extension::factory($grant_type, $arguments))
76 | {
77 | $response = $extension->execute();
78 | }
79 | }
80 |
81 | if(isset($response) AND $response instanceOf Oauthz_Token)
82 | {
83 | // HTTP/1.1 200 OK
84 | $this->request->status = 200;
85 | $this->request->headers['Content-Type'] = $response->format;
86 | }
87 | else
88 | {
89 | /**
90 | * HTTP/1.1 401 (Unauthorized) for "Authorization" request header field
91 | * HTTP/1.1 400 Bad Request for other authentication scheme
92 | */
93 | $this->request->status = 400;
94 |
95 | $params = Oauthz::get('state') ? array('state' => Oauthz::get('state')) : NULL;
96 |
97 | throw new Oauthz_Exception_Token('unsupported_grant_type', $params);
98 | }
99 | }
100 | catch (Oauthz_Exception $e)
101 | {
102 | $this->request->headers['Content-Type'] = 'application/json';
103 |
104 | $response = $e->as_json();
105 | }
106 |
107 | $this->request->headers['Expires'] = 'Sat, 26 Jul 1997 05:00:00 GMT';
108 | $this->request->headers['Cache-Control'] = 'no-store, must-revalidate';
109 | $this->request->response = $response;
110 | }
111 |
112 | } // END Oauthz Server Controller
113 |
--------------------------------------------------------------------------------
/config/oauth-server.php:
--------------------------------------------------------------------------------
1 | array(
8 |
9 | 'realm' => 'REST API',
10 |
11 | // '' - no login required, 'basic' - unsecure login, 'digest' - more secure login, 'OAuth' - cool
12 | 'auth' => 'OAuth',
13 |
14 | /**
15 | * Set to FALSE to ignore the HTTP Accept and speed up each request a little.
16 | * Only do this if you are using the follow formats or /format/xml in URLs
17 | */
18 | 'http_accept'=> FALSE,
19 |
20 | // login uri for the resource owner, before he approves the client's request
21 | // [!!] this uri will be appended the redirect parameter. therefore the last char must be '?' or '&'
22 | // e.g. /user/signin?, /user/signin?my=xxx&
23 | 'login_uri' => '/oauth/signin?',
24 |
25 | // Error info base uri
26 | 'error_uri' => '/oauth/error',
27 |
28 | /**
29 | * TODO: Authentication methods for each flows
30 | */
31 | 'methods' => array(
32 | 'authorization_code' => array('basic', 'digest', 'mac'),
33 | 'access_token' => array('bearer', 'mac'),
34 | ),
35 |
36 | /**
37 | * Parameters should be required when request authorization code
38 | * cryptographic token or bear token
39 | *
40 | * TRUE: the value of this parameter is obtained from request parameters
41 | * FALSE: this parameter is disabled
42 | * otherwise: this parameter will be binded to token object
43 | */
44 | 'params' => array(
45 | // Parameters should be required for response_type endpoint
46 | 'code' => array(
47 | 'client_id' => TRUE,
48 | 'redirect_uri' => TRUE,
49 | 'scope' => FALSE,
50 | 'state' => FALSE,
51 | // authorization code expires time, default is 2 minutes
52 | 'expires_in' => 60,
53 |
54 | // The follow Parameters are used for access token request
55 | 'token_type' => 'bearer'
56 | ),
57 | // Parameters should be required for grant_type endpoint
58 | 'authorization_code' => array(
59 | 'code' => TRUE,
60 | 'redirect_uri' => TRUE,
61 | 'client_id' => TRUE,
62 | 'client_secret' => TRUE,
63 | // authorization code expires time, default is 5 minutes
64 | 'expires_in' => 300
65 | ),
66 | 'token' => array(
67 | 'code' => TRUE,
68 | 'redirect_uri' => TRUE,
69 | 'client_id' => TRUE,
70 | 'client_secret' => TRUE,
71 | 'scope' => FALSE,
72 | 'state' => FALSE,
73 | 'mac_key' => FALSE,
74 | 'mac_algorithm' => FALSE,
75 | // token expires time, default is 1 hour
76 | 'expires_in' => 3600
77 | ),
78 | 'password' => array(
79 | 'username' => TRUE,
80 | 'password' => TRUE,
81 | 'client_id' => TRUE,
82 | 'client_secret' => TRUE,
83 | 'mac_key' => FALSE,
84 | 'mac_algorithm' => FALSE,
85 | // token expires time, default is 1 hour
86 | 'expires_in' => 3600
87 | ),
88 | 'refresh_token' => array(
89 | 'refresh_token' => TRUE,
90 | 'client_id' => TRUE,
91 | 'client_secret' => TRUE,
92 | 'mac_key' => FALSE,
93 | 'mac_algorithm' => FALSE,
94 | // refresh token expires time, default is 1 day
95 | 'expires_in' => 86400
96 | ),
97 | // TODO
98 | 'assertion' => array(
99 | 'assertion_type' => TRUE,
100 | 'assertion' => TRUE,
101 | 'client_id' => TRUE,
102 | 'client_secret' => TRUE
103 | )
104 | ),
105 | 'scopes' => array(
106 | 'get' => TRUE,
107 | 'create' => TRUE,
108 | 'update' => TRUE,
109 | 'delete' => TRUE
110 | )
111 | )
112 |
113 | ); // END OAuth server config
114 |
--------------------------------------------------------------------------------
/classes/oauthz/token.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * *
11 | */
12 | class Oauthz_Token {
13 |
14 | public $format = 'json';
15 |
16 | public function __construct(array $params = array())
17 | {
18 | foreach($params as $key => $val)
19 | {
20 | $this->$key = $val;
21 | }
22 | }
23 |
24 | public function as_json()
25 | {
26 | if(empty($this->error))
27 | {
28 | $json = get_object_vars($this);
29 | foreach($json as $key => $val)
30 | {
31 | if(empty($val)) unset($json[$key]);
32 | }
33 | }
34 | else
35 | {
36 | $json = array('error' => $this->error);
37 |
38 | isset($this->state) AND $json['state'] = $this->state;
39 | }
40 |
41 | // JSON_UNESCAPED_SLASHES
42 | return str_replace('\\/', '/', json_encode($json));
43 | }
44 |
45 | public function as_xml()
46 | {
47 | $doc = new DOMDocument('1.0', 'UTF-8');
48 | $doc->formatOutput = true;
49 |
50 | $oauth = $doc->createElement('OAuth');
51 | $doc->appendChild($oauth);
52 |
53 | if(empty($this->error))
54 | {
55 | foreach(get_object_vars($this) as $key => $val)
56 | {
57 | if(empty($val)) continue;
58 |
59 | $node = $doc->createElement($key);
60 | $node->appendChild($doc->createTextNode($val));
61 | $oauth->appendChild($node);
62 | }
63 | }
64 | else
65 | {
66 | $node = $doc->createElement('error');
67 | $node->appendChild($doc->createTextNode($this->error));
68 | $oauth->appendChild($node);
69 |
70 | if(isset($this->state))
71 | {
72 | $node = $doc->createElement('state');
73 | $node->appendChild($doc->createTextNode($this->state));
74 | $oauth->appendChild($node);
75 | }
76 | }
77 | return $doc->saveXML();
78 | }
79 |
80 | public function as_query()
81 | {
82 | if(empty($this->error))
83 | {
84 | $form = get_object_vars($this);
85 | foreach($form as $key => $val)
86 | {
87 | if(empty($val)) unset($form[$key]);
88 | }
89 | }
90 | else
91 | {
92 | $form = array('error' => $this->error);
93 |
94 | isset($this->state) AND $form['state'] = $this->state;
95 |
96 | isset($this->error_uri) AND $form['error_uri'] = $this->error_uri;
97 |
98 | isset($this->error_description) AND $form['error_description'] = $this->error_description;
99 | }
100 | return http_build_query($form, '', '&');
101 | }
102 |
103 | public function as_html()
104 | {
105 | $text = '';
106 | if(empty($this->error))
107 | {
108 | $form = get_object_vars($this);
109 | foreach($form as $key => $val)
110 | {
111 | if(empty($val)) continue;
112 |
113 | $text .= ''.$key.' '.$val.' ';
114 | }
115 | }
116 | else
117 | {
118 | $text .= 'error '.$this->error.' ';
119 |
120 | isset($this->state) AND $text .= 'state '.$this->state.' ';
121 | }
122 | return $text.' ';
123 | }
124 |
125 | /**
126 | * Serialize token to string that a server would respond to
127 | *
128 | * @access public
129 | * @return string
130 | */
131 | public function __toString()
132 | {
133 | $format = $this->format;
134 | $this->format = NULL;
135 | switch($format)
136 | {
137 | case 'xml':
138 | case 'application/xhtml+xml':
139 | $res = $this->as_xml();
140 | $this->format = 'application/xml';
141 | break;
142 | case 'form':
143 | $res = $this->as_query();
144 | $this->format = 'application/x-www-form-urlencoded';
145 | break;
146 | case 'text/html':
147 | $res = $this->as_html();
148 | $this->format = 'text/html';
149 | break;
150 | default:
151 | $res = $this->as_json();
152 | $this->format = 'application/json';
153 | break;
154 | }
155 | return $res;
156 | }
157 |
158 | public function __set($key, $val)
159 | {
160 | if( ! empty($val)) $this->$key = $val;
161 | }
162 |
163 | } // END Oauthz_Token
164 |
--------------------------------------------------------------------------------
/classes/oauthz/extension/authorization/code.php:
--------------------------------------------------------------------------------
1 |
8 | * @package Oauthz
9 | * @copyright (c) 2010 OALite
10 | * @license ISC License (ISCL)
11 | * @link http://oalite.com
12 | * @see Oauthz_Extension
13 | * *
14 | */
15 | class Oauthz_Extension_Authorization_Code extends Oauthz_Extension {
16 |
17 | /**
18 | * REQUIRED. The client identifier as described in Section 2.1.
19 | *
20 | * @access public
21 | * @var string $client_id
22 | */
23 | public $client_id;
24 |
25 | /**
26 | * REQUIRED. The redirection URI used in the initial request.
27 | *
28 | * @access public
29 | * @var string $redirect_uri
30 | */
31 | public $redirect_uri;
32 |
33 | /**
34 | * Load oauth parameters from GET or POST
35 | *
36 | * @access public
37 | * @param string $flag default [ FALSE ]
38 | * @return void
39 | */
40 | public function __construct(array $args)
41 | {
42 | // Parse the "state" paramter
43 | if(isset($_POST['state']))
44 | {
45 | if($state = rawurldecode($_POST['state']))
46 | $this->state['state'] = $state;
47 |
48 | unset($args['state']);
49 | }
50 |
51 | // Check all required parameters should NOT be empty
52 | foreach($args as $key => $val)
53 | {
54 | if($val === TRUE)
55 | {
56 | if(isset($_POST[$key]) AND $value = rawurldecode($_POST[$key]))
57 | {
58 | $this->$key = $value;
59 | }
60 | else
61 | {
62 | throw new Oauthz_Exception_Authorize('invalid_request', $this->state);
63 | }
64 | }
65 | elseif($val !== FALSE)
66 | {
67 | $this->$key = $val;
68 | }
69 | }
70 | }
71 |
72 | /**
73 | * Populate the access token thu the request info and client info stored in the server
74 | *
75 | * @access public
76 | * @param array $client
77 | * @return Oauthz_Token
78 | * @throw Oauthz_Exception_Authorize Error Codes: invalid_request, invalid_scope
79 | */
80 | public function execute()
81 | {
82 | if($client = Model_Oauthz::factory('Token')
83 | ->token($this->client_id, $this->code, $this->expires_in))
84 | {
85 | //$audit = new Model_Oauthz_Audit;
86 | //$audit->audit_token($token);
87 |
88 | // Verify the oauth token send by client
89 | }
90 | else
91 | {
92 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
93 | }
94 |
95 | if($client['redirect_uri'] !== $this->redirect_uri)
96 | {
97 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
98 | }
99 |
100 | if($client['client_secret'] !== sha1($this->client_secret))
101 | {
102 | // Redirect to client uri
103 | $params = $this->state;
104 | $params['error_uri'] = $this->redirect_uri;
105 |
106 | throw new Oauthz_Exception_Token('unauthorized_client', $params);
107 | }
108 |
109 | if( ! empty($this->scope) AND ! empty($client['scope']))
110 | {
111 | if( ! in_array($this->scope, explode(' ', $client['scope'])))
112 | {
113 | $params = $this->state;
114 | $params['error_uri'] = $this->redirect_uri;
115 |
116 | throw new Oauthz_Exception_Authorize('invalid_scope', $params);
117 | }
118 | }
119 |
120 | if($client['expires_in'] < $_SERVER['REQUEST_TIME'])
121 | {
122 | $params = $this->state;
123 | $params['error_uri'] = $this->redirect_uri;
124 |
125 | throw new Oauthz_Exception_Access('invalid_grant', $params);
126 | }
127 |
128 | // Everything is ok, then return the token
129 | $token = new Oauthz_Token;
130 |
131 | // TODO: issue "mac" OAuth Access Token Type
132 | $token->token_type = $client['token_type'];
133 | $token->access_token = $client['access_token'];
134 | $token->refresh_token = $client['refresh_token'];
135 | $token->expires_in = $client['expires_in'];
136 |
137 | // merge other token properties, e.g. {"mac_key":"adijq39jdlaska9asud","mac_algorithm":"hmac-sha-256"}
138 | if($client['options'] AND $option = json_decode($client['options'], TRUE))
139 | {
140 | foreach($option as $key => $val)
141 | {
142 | $token->$key = $val;
143 | }
144 | }
145 |
146 | isset($this->state['state']) AND $token->state = $this->state['state'];
147 |
148 | return $token;
149 | }
150 |
151 | } // END Oauthz_Extension_Authorization_Code
152 |
--------------------------------------------------------------------------------
/classes/oauthz/api.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Kohana_Controller
11 | * *
12 | */
13 | abstract class Oauthz_Api extends Kohana_Controller {
14 |
15 | /**
16 | * Config group name
17 | *
18 | * @access protected
19 | * @var string $_type
20 | */
21 | protected $_type = 'default';
22 |
23 | /**
24 | * methods exclude from OAuth protection
25 | *
26 | * @access protected
27 | * @var array $_exclude
28 | */
29 | protected $_exclude = array('xrds');
30 |
31 | /**
32 | * Verify the request to protected resource.
33 | * if unauthorized, redirect action to invalid_request
34 | *
35 | * @access public
36 | * @return void
37 | */
38 | public function __construct(Request $request)
39 | {
40 | // Exclude actions do NOT need to protect
41 | if( ! in_array($request->action, $this->_exclude))
42 | {
43 | $config = Kohana::config('oauth-api')->get($this->_type);
44 |
45 | switch(Request::$method)
46 | {
47 | case 'POST':
48 | $target = $_POST;
49 | break;
50 | case 'GET':
51 | $target = $_GET;
52 | break;
53 | }
54 |
55 | try
56 | {
57 | // Verify the request method supported in the config settings
58 | if( ! isset($target) OR empty($config['methods'][Request::$method]))
59 | {
60 | throw new Oauthz_Exception_Access('invalid_request', Oauthz_Authentication::state($target));
61 | }
62 |
63 | $token_type = Arr::get($target, 'token_type', 'bearer');
64 |
65 | if( ! isset($config[$token_type]))
66 | {
67 | throw new Oauthz_Exception_Access('invalid_grant', Oauthz_Authentication::state($target));
68 | }
69 |
70 | // Process the access token from the request header or body
71 | $oauth = Oauthz_Authentication::factory($token_type, $config[$token_type], $target);
72 |
73 | // Load the token information from database
74 | if( ! $token = Model_Oauthz::factory('Token')
75 | ->access_token($oauth->token()))
76 | {
77 | throw new Oauthz_Exception_Access('unauthorized_client', Oauthz_Authentication::state($target));
78 | }
79 |
80 | if($token['expires_in'] < $_SERVER['REQUEST_TIME'])
81 | {
82 | throw new Oauthz_Exception_Access('invalid_grant', Oauthz_Authentication::state($target));
83 | }
84 |
85 | // Verify the access token
86 | $oauth->verify($token);
87 | }
88 | catch (Oauthz_Exception $e)
89 | {
90 | $this->exception = $e;
91 |
92 | // Redirect the action to unauthenticated
93 | $request->action = 'unauthenticated';
94 | }
95 | }
96 |
97 | parent::__construct($request);
98 | }
99 |
100 | /**
101 | * Unauthorized response, only be called from internal
102 | *
103 | * @access public
104 | * @param string $error
105 | * @return void
106 | * @todo Add list of error codes
107 | */
108 | public function action_unauthenticated()
109 | {
110 | if($this->exception->error === 'invalid_client')
111 | {
112 | // HTTP/1.1 401 Unauthorized
113 | $this->request->status = 401;
114 | // TODO: If the client attempted to authenticate via the "Authorization" request header field
115 | // the "WWW-Authenticate" response header field matching the authentication scheme used by the client.
116 | // $this->request->headers['WWW-Authenticate'] = 'OAuth2 realm=\'Service\','.http_build_query($error, '', ',');
117 | }
118 | else
119 | {
120 | // HTTP/1.1 400 Bad Request
121 | $this->request->status = 400;
122 | }
123 |
124 | $this->request->headers['Content-Type'] = 'application/json';
125 | $this->request->headers['Expires'] = 'Sat, 26 Jul 1997 05:00:00 GMT';
126 | $this->request->headers['Cache-Control'] = 'no-store, must-revalidate';
127 | $this->request->response = $this->exception->as_json();
128 | }
129 |
130 | /**
131 | * OAuth server auto-discovery for user
132 | *
133 | * @access public
134 | * @return void
135 | * @todo Add list of error codes
136 | */
137 | public function action_xrds()
138 | {
139 | $this->request->headers['Content-Type'] = 'application/xrds+xml';
140 | $this->request->response = View::factory('oauth-server-xrds')->render();
141 | }
142 |
143 | } // END Oauthz_Api
144 |
--------------------------------------------------------------------------------
/views/oauthz-template.php:
--------------------------------------------------------------------------------
1 | get('user');
3 | ?>
4 |
5 |
6 |
7 |
8 |
9 | OAuth Test
10 |
11 |
12 |
13 |
99 |
100 |
101 |
102 |
103 |
104 | OAuth 2.0 Test
105 |
119 |
120 |
121 |
122 |
124 |
125 |
126 |
127 |
128 | OALite Inc.
129 |
130 | Open Application Lite is a web platform that offers online software serivce to personal and medium and small-sized enterprises.
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/doc/oauth-mysql.sql:
--------------------------------------------------------------------------------
1 | /**
2 | * OAuth database table schema for MySQL
3 | *
4 | * @author sumh <42424861@qq.com>
5 | * @package Oauth
6 | * @copyright (c) 2011 OALite
7 | * @license ISC License (ISCL)
8 | * @link http://oalite.com
9 | */
10 |
11 | /******************** Add Table: t_oauth_authorizes ************************/
12 |
13 | /* Build Table Structure */
14 | CREATE TABLE t_oauth_authorizes
15 | (
16 | user_id BIGINT UNSIGNED NULL,
17 | client_id VARCHAR(127) NOT NULL,
18 | redirect_uri VARCHAR(511) NOT NULL,
19 | confirm_type TINYINT UNSIGNED DEFAULT 0
20 | COMMENT 'Request confirm, 0: every time; 1: only once; 2: with expired period; 3: once and banned' NOT NULL,
21 | client_level TINYINT UNSIGNED DEFAULT 0
22 | COMMENT 'diferent client levels have different max request times' NOT NULL,
23 | client_desc TEXT NULL,
24 | expires_in INTEGER UNSIGNED
25 | COMMENT 'date time' NULL,
26 | scope VARCHAR(511) NULL,
27 | created INTEGER UNSIGNED NOT NULL,
28 | modified INTEGER UNSIGNED NULL,
29 | remark TEXT NULL
30 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
31 |
32 | /* Table Items: t_oauth_authorizes */
33 | ALTER TABLE t_oauth_authorizes ADD CONSTRAINT pkt_oauth_authorizes
34 | PRIMARY KEY (user_id);
35 |
36 | /* Set Comments */
37 | ALTER TABLE t_oauth_authorizes COMMENT = 'Store audit information from resource owner for the resource requester';
38 |
39 | /******************** Add Table: t_oauth_clients ************************/
40 |
41 | /* Build Table Structure */
42 | CREATE TABLE t_oauth_clients
43 | (
44 | server_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
45 | client_id VARCHAR(127)
46 | COMMENT 'AKA. API key' NOT NULL,
47 | client_secret VARCHAR(127)
48 | COMMENT 'AKA. API secret' NOT NULL,
49 | redirect_uri VARCHAR(511)
50 | COMMENT 'AKA. Callback URI' NOT NULL,
51 | scope VARCHAR(255)
52 | COMMENT 'May be create, read, update or delete. so on so for' NULL,
53 | secret_type ENUM('plaintext','md5','rsa-sha1','hmac-sha1') DEFAULT 'plaintext'
54 | COMMENT 'Secret signature encrypt type. e.g' NOT NULL,
55 | ssh_key VARCHAR(511)
56 | COMMENT 'SSH public keys' NULL,
57 | app_name VARCHAR(127)
58 | COMMENT 'Application Name' NOT NULL,
59 | app_desc TEXT
60 | COMMENT 'Application Description, When users authenticate via your app, this is what they\'ll see.' NULL,
61 | app_profile ENUM('webserver','native','useragent','autonomous') DEFAULT 'webserver'
62 | COMMENT 'Application Profile: Web Server Application, Native Application, Browser Application, Autonomous clients' NOT NULL,
63 | app_purpose VARCHAR(511) NULL,
64 | user_id BIGINT UNSIGNED
65 | COMMENT 'Ref# from users table' NULL,
66 | user_level TINYINT UNSIGNED DEFAULT 0
67 | COMMENT 'diferent client levels have different max request times' NOT NULL,
68 | enabled TINYINT UNSIGNED DEFAULT 1
69 | COMMENT '0: waiting for system administrator audit; 1: acceptable; 2: ban' NOT NULL,
70 | created INTEGER UNSIGNED
71 | COMMENT 'create datetime' NOT NULL,
72 | modified INTEGER UNSIGNED
73 | COMMENT 'modified datetime' NULL
74 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
75 |
76 | /* Table Items: t_oauth_clients */
77 |
78 | /* Set Comments */
79 | ALTER TABLE t_oauth_clients COMMENT = 'Used for verification of incoming requests. ';
80 |
81 | /* Add Indexes for: t_oauth_clients */
82 | CREATE UNIQUE INDEX idx_t_oauth_clients_client_id ON t_oauth_clients (client_id);
83 |
84 | /******************** Add Table: t_oauth_logs ************************/
85 |
86 | /* Build Table Structure */
87 | CREATE TABLE t_oauth_logs
88 | (
89 | log_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
90 | client_id VARCHAR(127) NULL,
91 | token VARCHAR(63) NULL,
92 | user_id BIGINT UNSIGNED NULL,
93 | received TEXT NOT NULL,
94 | sent TEXT NOT NULL,
95 | body TEXT NOT NULL,
96 | notes TEXT NOT NULL,
97 | `timestamp` TIMESTAMP NOT NULL,
98 | remote_ip BIGINT NOT NULL
99 | ) DEFAULT CHARSET=utf8;
100 |
101 | /* Table Items: t_oauth_logs */
102 |
103 | /* Set Comments */
104 | ALTER TABLE t_oauth_logs COMMENT = 'Log table to hold all OAuth request when you enabled logging ';
105 |
106 | /* Add Indexes for: t_oauth_logs */
107 | CREATE INDEX idx_t_oauth_logs_client_id_log_id ON t_oauth_logs (client_id, log_id);
108 |
109 | /******************** Add Table: t_oauth_tokens ************************/
110 |
111 | /* Build Table Structure */
112 | CREATE TABLE t_oauth_tokens
113 | (
114 | token_id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
115 | client_id VARCHAR(127) NOT NULL,
116 | user_id BIGINT UNSIGNED
117 | COMMENT 'Ref# from users table' NOT NULL,
118 | code VARCHAR(127) NOT NULL,
119 | access_token VARCHAR(63) NULL,
120 | refresh_token VARCHAR(63) NULL,
121 | expire_code INTEGER UNSIGNED DEFAULT 300
122 | COMMENT 'authorization code expires in this timestamp' NOT NULL,
123 | expire_token INTEGER UNSIGNED DEFAULT 0
124 | COMMENT 'access token expires in this timestamp' NOT NULL,
125 | expire_refresh INTEGER UNSIGNED DEFAULT 0
126 | COMMENT 'refresh token expires in this timestamp' NOT NULL,
127 | `timestamp` INTEGER UNSIGNED
128 | COMMENT 'authorization code request timestamp' NOT NULL,
129 | token_type VARCHAR(127)
130 | COMMENT 'bearer, mac, etc.' NOT NULL,
131 | options TEXT
132 | COMMENT 'parameters for different token type extension in json format' NULL
133 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
134 |
135 | /* Table Items: t_oauth_tokens */
136 |
137 | /* Set Comments */
138 | ALTER TABLE t_oauth_tokens COMMENT = 'Table used to verify signed requests sent to a server by the consumer.When the verification is succesful then the associated user id is returned. ';
139 |
140 | /* Add Indexes for: t_oauth_tokens */
141 | CREATE INDEX idx_t_oauth_tokens_access_token ON t_oauth_tokens (access_token);
142 | CREATE INDEX idx_t_oauth_tokens_client_id ON t_oauth_tokens (client_id);
143 | CREATE INDEX idx_t_oauth_tokens_code ON t_oauth_tokens (code);
144 | CREATE INDEX idx_t_oauth_tokens_refresh_token ON t_oauth_tokens (refresh_token);
145 |
146 |
147 | /************ Add Foreign Keys to Database ***************/
148 |
149 | /************ Foreign Key: fk_t_oauth_tokens_t_oauth_clients ***************/
150 | ALTER TABLE t_oauth_tokens ADD CONSTRAINT fk_t_oauth_tokens_t_oauth_clients
151 | FOREIGN KEY (client_id) REFERENCES t_oauth_clients (client_id)
152 | ON UPDATE CASCADE ON DELETE CASCADE;
--------------------------------------------------------------------------------
/classes/oauthz/extension/refresh/token.php:
--------------------------------------------------------------------------------
1 |
8 | * @package Oauthz
9 | * @copyright (c) 2010 OALite
10 | * @license ISC License (ISCL)
11 | * @link http://oalite.com
12 | * @see Oauthz_Extension
13 | * *
14 | */
15 | class Oauthz_Extension_Refresh_Token extends Oauthz_Extension {
16 |
17 | /**
18 | * client_id
19 | * REQUIRED. The client identifier
20 | */
21 | public $client_id;
22 |
23 | /**
24 | * client_secret
25 | * REQUIRED. The client secret
26 | * OPTIONAL if no client secret was issued.
27 | */
28 | public $client_secret;
29 |
30 | /**
31 | * redirect_uri
32 | * REQUIRED unless a redirection URI has been established between
33 | * the client and authorization server via other means. An
34 | * absolute URI to which the authorization server will redirect
35 | * the user-agent to when the end-user authorization step is
36 | * completed. The authorization server SHOULD require the client
37 | * to pre-register their redirection URI. Authorization servers
38 | * MAY restrict the redirection URI to not include a query
39 | * component as defined by [RFC3986] section 3.
40 | */
41 | public $redirect_uri;
42 |
43 | /**
44 | * state
45 | * OPTIONAL. An opaque value used by the client to maintain state
46 | * between the request and callback. The authorization server
47 | * includes this value when redirecting the user-agent back to the
48 | * client.
49 | *
50 | * scope
51 | * OPTIONAL. The scope of the access request expressed as a list
52 | * of space-delimited strings. The value of the "scope" parameter
53 | * is defined by the authorization server. If the value contains
54 | * multiple space-delimited strings, their order does not matter,
55 | * and each string adds an additional access range to the
56 | * requested scope.
57 | *
58 | * @access public
59 | * @return void
60 | * @throw Oauthz_Exception_Token Error Codes: invalid_request
61 | */
62 | public function __construct($args = NULL)
63 | {
64 | isset($_SERVER['CONTENT_TYPE']) OR $_SERVER['CONTENT_TYPE'] = getenv('CONTENT_TYPE');
65 |
66 | // Parse the "state" paramter
67 | if(isset($_POST['state']))
68 | {
69 | if($state = rawurldecode($_POST['state']))
70 | $this->state['state'] = $state;
71 |
72 | unset($args['state']);
73 | }
74 |
75 | // oauth_token already send in authorization header or the encrypt Content-Type is not single-part
76 | if(empty($_POST) OR stripos($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') === FALSE)
77 | {
78 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
79 | }
80 | else
81 | {
82 | if(isset($_SERVER['PHP_AUTH_USER']) AND isset($_SERVER['PHP_AUTH_PW']))
83 | {
84 | $_POST += array('username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']);
85 | }
86 | // TODO Digest HTTP authentication
87 | //else if( ! empty($_SERVER['PHP_AUTH_DIGEST']) AND $digest = parent::parse_digest($_SERVER['PHP_AUTH_DIGEST']))
88 | //{
89 | // $_POST += array('username' => $digest['username'], 'password' => $digest['']);
90 | //}
91 |
92 | // Check all required parameters from form-encoded body
93 | foreach($args as $key => $val)
94 | {
95 | if($val === TRUE)
96 | {
97 | if(isset($_POST[$key]) AND $value = rawurldecode($_POST[$key]))
98 | {
99 | $this->$key = $value;
100 | }
101 | else
102 | {
103 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
104 | }
105 | }
106 | }
107 | }
108 | }
109 |
110 | /**
111 | * TODO Refresh token
112 | *
113 | * @access public
114 | * @param array $client
115 | * @return Oauthz_Token
116 | * @throw Oauthz_Exception_Authorize Error Codes: invalid_request, invalid_scope
117 | */
118 | public function execute()
119 | {
120 | if($client = Model_Oauthz::factory('Client')->lookup($this->client_id))
121 | {
122 | // Verify the user information send by client
123 | }
124 | else
125 | {
126 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
127 | }
128 |
129 | if($client['redirect_uri'] !== $this->redirect_uri)
130 | {
131 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
132 | }
133 |
134 | if($client['client_secret'] !== sha1($this->client_secret))
135 | {
136 | $params = $this->state;
137 | $params['error_uri'] = $this->redirect_uri;
138 |
139 | throw new Oauthz_Exception_Token('invalid_request', $params);
140 | }
141 |
142 | if(isset($this->scope) AND ! empty($client['scope']))
143 | {
144 | if( ! in_array($this->scope, explode(' ', $client['scope'])))
145 | {
146 | $params = $this->state;
147 | $params['error_uri'] = $this->redirect_uri;
148 |
149 | throw new Oauthz_Exception_Token('invalid_scope', $params);
150 | }
151 | }
152 |
153 | $token = new Oauthz_Token;
154 |
155 | $token->token_type = $client['token_type'];
156 | $token->access_token = $client['access_token'];
157 | $token->refresh_token = $client['refresh_token'];
158 |
159 | // merge other token properties, e.g. {"mac_key":"adijq39jdlaska9asud","mac_algorithm":"hmac-sha-256"}
160 | if($client['options'] AND $option = json_decode($client['options'], TRUE))
161 | {
162 | foreach($option as $key => $val)
163 | {
164 | $token->$key = $val;
165 | }
166 | }
167 |
168 | isset($this->state['state']) AND $token->state = $this->state['state'];
169 |
170 | return $token;
171 | }
172 |
173 | } // END Oauthz_Extension_Client_Credentials
174 |
--------------------------------------------------------------------------------
/classes/oauthz/client.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Kohana_Controller
11 | * *
12 | */
13 | class Oauthz_Client extends Kohana_Controller {
14 |
15 | /**
16 | * provider config group name
17 | *
18 | * @access protected
19 | * @var string $provider
20 | */
21 | protected $_type = 'default';
22 |
23 | /**
24 | * Request settings for OAuth
25 | *
26 | * @access protected
27 | * @var string $_configs
28 | */
29 | protected $_configs = null;
30 |
31 | public function before()
32 | {
33 | $this->_configs = Kohana::config('oauth-client')->get($this->_type);
34 | }
35 |
36 | /* Obtain an an Authorization Code, ONLY for Authorization Code flow */
37 | public function action_code($uri = NULL)
38 | {
39 | $type = $this->_configs['protocol-flow'];
40 |
41 | if($type !== 'code')
42 | {
43 | // Redirect to correct action
44 | if(isset($this->_configs[$type]))
45 | {
46 | $this->request->redirect('client/do'.($uri ? "/$uri" : ''));
47 | }
48 | else
49 | {
50 | $template = new View('oauthz-template');
51 | $template->content = 'Unsupported protocal flow, please check your oauth-client.php config.';
52 | return $this->request->response = $template;
53 | }
54 | }
55 |
56 | empty($uri) AND $uri = $this->_configs['oauth-uri'];
57 |
58 | // Load the paramtes and remove all empty ones
59 | $params = array_filter($this->_configs['code']);
60 | $params['response_type'] = 'code';
61 |
62 | // Don't expose the client_secret
63 | unset($params['client_secret']);
64 |
65 | $this->request->redirect($uri.'?'.http_build_query($params, '', '&'));
66 | }
67 |
68 | /* Request an access token and then access the protected resource */
69 | public function action_do($uri = NULL)
70 | {
71 | $template = new View('oauthz-template');
72 |
73 | try
74 | {
75 | $token = $this->token($uri);
76 |
77 | $param = array(
78 | CURLOPT_POST => TRUE,
79 | CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded;charset=utf-8'),
80 | CURLOPT_POSTFIELDS => http_build_query($token, '', '&')
81 | );
82 |
83 | // Resource in json format
84 | $api_uri = $this->_configs['api-uri'].'get';
85 | $hello = Remote::get($api_uri, $param);
86 | $resaults['first'] = array(
87 | 'uri' => $api_uri,
88 | 'info' => $hello,
89 | 'token' => $token['access_token']
90 | );
91 |
92 | // we try to use this token to request another more information
93 | $api_uri = $this->_configs['api-uri'].'get/1';
94 | $world = Remote::get($api_uri, $param);
95 | $resaults['second'] = array(
96 | 'uri' => $api_uri,
97 | 'info' => $world,
98 | 'token' => $token['access_token']
99 | );
100 |
101 | $template->content = new View('oauthz-client-response', $resaults);
102 | }
103 | catch(Exception $e)
104 | {
105 | $error = $e->getMessage();
106 |
107 | switch($error)
108 | {
109 | case 'access_denied':
110 | $template->content = 'You have denied this request.';
111 | break;
112 | default:
113 | $template->content = "There must be some errors happen in this connection,
114 | please contact our web master. error code : [$error]";
115 | empty($e->error_description) OR $template->content .= ", description : [$e->error_description]";
116 | break;
117 | }
118 | }
119 | $this->request->response = $template;
120 | }
121 |
122 | /* Obtain an Access Token */
123 | protected function token($uri = NULL)
124 | {
125 | empty($uri) OR $uri = $this->_configs['oauth-uri'];
126 |
127 | $type = $this->_configs['protocol-flow'];
128 |
129 | if(isset($this->_configs[$type]))
130 | {
131 | $params = $this->_configs[$type];
132 | switch($type)
133 | {
134 | case 'code':
135 | if(empty($_GET['code']))
136 | {
137 | throw new Oauthz_Exception(isset($_GET['error']) ? $_GET['error'] : 'Unknow error');
138 | }
139 | $params['code'] = $_GET['code'];
140 | $params['grant_type'] = 'authorization_code';
141 | break;
142 | case 'token':
143 | $params['response_type'] = 'token';
144 | break;
145 | case 'password':
146 | $params['grant_type'] = 'password';
147 | break;
148 | case 'client_credentials':
149 | $params['grant_type'] = 'client_credentials';
150 | break;
151 | }
152 |
153 | // Request access token
154 | $token = Remote::get($this->_configs['token-uri'], array(
155 | CURLOPT_POST => TRUE,
156 | CURLOPT_HTTPHEADER => array('Content-Type: application/x-www-form-urlencoded;charset=utf-8'),
157 | CURLOPT_POSTFIELDS => http_build_query($params, '', '&')
158 | ));
159 |
160 | $token = json_decode($token, TRUE);
161 |
162 | if(isset($token['error']))
163 | {
164 | throw new Oauthz_Exception_Access($token['error'], $token);
165 | }
166 |
167 | // Store the client info into the token
168 | $token['client_id'] = $params['client_id'];
169 | $token['client_secret'] = $params['client_secret'];
170 |
171 | return $token;
172 | }
173 |
174 | throw new Oauthz_Exception('Unsupported protocal flow, please check your oauth-client.php config.');
175 | }
176 |
177 | /* Refreshing an Access Token */
178 | protected function refresh_token(array $token)
179 | {
180 | // TODo
181 | }
182 |
183 | } // END Oauthz Client Controller
184 |
--------------------------------------------------------------------------------
/classes/oauthz/extension/client/credentials.php:
--------------------------------------------------------------------------------
1 |
8 | * @package Oauthz
9 | * @copyright (c) 2010 OALite
10 | * @license ISC License (ISCL)
11 | * @link http://oalite.com
12 | * @see Oauthz_Extension
13 | * *
14 | */
15 | class Oauthz_Extension_Client_Credentials extends Oauthz_Extension {
16 |
17 | /**
18 | * client_id
19 | * REQUIRED. The client identifier
20 | */
21 | public $client_id;
22 |
23 | /**
24 | * client_secret
25 | * REQUIRED. The client secret
26 | * OPTIONAL if no client secret was issued.
27 | */
28 | public $client_secret;
29 |
30 | /**
31 | * redirect_uri
32 | * REQUIRED unless a redirection URI has been established between
33 | * the client and authorization server via other means. An
34 | * absolute URI to which the authorization server will redirect
35 | * the user-agent to when the end-user authorization step is
36 | * completed. The authorization server SHOULD require the client
37 | * to pre-register their redirection URI. Authorization servers
38 | * MAY restrict the redirection URI to not include a query
39 | * component as defined by [RFC3986] section 3.
40 | */
41 | public $redirect_uri;
42 |
43 | /**
44 | * state
45 | * OPTIONAL. An opaque value used by the client to maintain state
46 | * between the request and callback. The authorization server
47 | * includes this value when redirecting the user-agent back to the
48 | * client.
49 | *
50 | * scope
51 | * OPTIONAL. The scope of the access request expressed as a list
52 | * of space-delimited strings. The value of the "scope" parameter
53 | * is defined by the authorization server. If the value contains
54 | * multiple space-delimited strings, their order does not matter,
55 | * and each string adds an additional access range to the
56 | * requested scope.
57 | *
58 | * @access public
59 | * @return void
60 | * @throw Oauthz_Exception_Token Error Codes: invalid_request
61 | */
62 | public function __construct($args = NULL)
63 | {
64 | isset($_SERVER['CONTENT_TYPE']) OR $_SERVER['CONTENT_TYPE'] = getenv('CONTENT_TYPE');
65 |
66 | // Parse the "state" paramter
67 | if(isset($_POST['state']))
68 | {
69 | if($state = trim($_POST['state']))
70 | $this->state['state'] = $state;
71 |
72 | unset($args['state']);
73 | }
74 |
75 | // oauth_token already send in authorization header or the encrypt Content-Type is not single-part
76 | if(empty($_POST) OR stripos($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') === FALSE)
77 | {
78 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
79 | }
80 | else
81 | {
82 | if(isset($_SERVER['PHP_AUTH_USER']) AND isset($_SERVER['PHP_AUTH_PW']))
83 | {
84 | $_POST += array('username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']);
85 | }
86 | // TODO Digest HTTP authentication
87 | //else if( ! empty($_SERVER['PHP_AUTH_DIGEST']) AND $digest = parent::parse_digest($_SERVER['PHP_AUTH_DIGEST']))
88 | //{
89 | // $_POST += array('username' => $digest['username'], 'password' => $digest['']);
90 | //}
91 |
92 | // Check all required parameters from form-encoded body
93 | foreach($args as $key => $val)
94 | {
95 | if($val === TRUE)
96 | {
97 | if(isset($_POST[$key]) AND $value = trim($_POST[$key]))
98 | {
99 | $this->$key = $value;
100 | }
101 | else
102 | {
103 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
104 | }
105 | }
106 | }
107 | }
108 | }
109 |
110 | /**
111 | * Populate the access token thu the request info and client info stored in the server
112 | *
113 | * @access public
114 | * @param array $client
115 | * @return Oauthz_Token
116 | * @throw Oauthz_Exception_Authorize Error Codes: invalid_request, invalid_scope
117 | */
118 | public function execute()
119 | {
120 | if($client = Model_Oauthz::factory('Client')->lookup($this->client_id))
121 | {
122 | // Verify the user information send by client
123 | }
124 | else
125 | {
126 | // Invalid client_id
127 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
128 | }
129 |
130 | if($client['redirect_uri'] !== $this->redirect_uri)
131 | {
132 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
133 | }
134 |
135 | if($client['client_secret'] !== sha1($this->client_secret))
136 | {
137 | $params = $this->state;
138 | $params['error_uri'] = $this->redirect_uri;
139 |
140 | throw new Oauthz_Exception_Token('invalid_request', $params);
141 | }
142 |
143 | if(isset($this->scope) AND ! empty($client['scope']))
144 | {
145 | if( ! in_array($this->scope, explode(' ', $client['scope'])))
146 | {
147 | $params = $this->state;
148 | $params['error_uri'] = $this->redirect_uri;
149 |
150 | throw new Oauthz_Exception_Token('invalid_scope', $params);
151 | }
152 | }
153 |
154 | if($client['expires_in'] < $_SERVER['REQUEST_TIME'])
155 | {
156 | throw new Oauthz_Exception_Access('invalid_grant', $this->state);
157 | }
158 |
159 | $token = new Oauthz_Token;
160 |
161 | // TODO: issue "mac" OAuth Access Token Type
162 | $token->token_type = $client['token_type'];
163 | $token->access_token = $client['access_token'];
164 | $token->refresh_token = $client['refresh_token'];
165 | $token->expires_in = $client['expires_in'];
166 |
167 | // merge other token properties, e.g. {"mac_key":"adijq39jdlaska9asud","mac_algorithm":"hmac-sha-256"}
168 | if($client['options'] AND $option = json_decode($client['options'], TRUE))
169 | {
170 | foreach($option as $key => $val)
171 | {
172 | $token->$key = $val;
173 | }
174 | }
175 |
176 | isset($this->state['state']) AND $token->state = $this->state['state'];
177 |
178 | return $token;
179 | }
180 |
181 | } // END Oauthz_Extension_Client_Credentials
182 |
--------------------------------------------------------------------------------
/classes/oauthz/extension/password.php:
--------------------------------------------------------------------------------
1 |
8 | * @package Oauthz
9 | * @copyright (c) 2010 OALite
10 | * @license ISC License (ISCL)
11 | * @link http://oalite.com
12 | * @see Oauthz_Extension
13 | * *
14 | */
15 | class Oauthz_Extension_Password extends Oauthz_Extension {
16 |
17 | /**
18 | * client_id
19 | * REQUIRED. The client identifier
20 | */
21 | public $client_id;
22 |
23 | /**
24 | * client_secret
25 | * REQUIRED. The client secret
26 | * OPTIONAL if no client secret was issued.
27 | */
28 | public $client_secret;
29 |
30 | /**
31 | * username
32 | * REQUIRED. The end-user's username.
33 | */
34 | public $username;
35 |
36 | /**
37 | * password
38 | * REQUIRED. The end-user's password.
39 | */
40 | public $password;
41 |
42 | /**
43 | * redirect_uri
44 | * REQUIRED unless a redirection URI has been established between
45 | * the client and authorization server via other means. An
46 | * absolute URI to which the authorization server will redirect
47 | * the user-agent to when the end-user authorization step is
48 | * completed. The authorization server SHOULD require the client
49 | * to pre-register their redirection URI. Authorization servers
50 | * MAY restrict the redirection URI to not include a query
51 | * component as defined by [RFC3986] section 3.
52 | */
53 | public $redirect_uri;
54 |
55 | /**
56 | * state
57 | * OPTIONAL. An opaque value used by the client to maintain state
58 | * between the request and callback. The authorization server
59 | * includes this value when redirecting the user-agent back to the
60 | * client.
61 | *
62 | * scope
63 | * OPTIONAL. The scope of the access request expressed as a list
64 | * of space-delimited strings. The value of the "scope" parameter
65 | * is defined by the authorization server. If the value contains
66 | * multiple space-delimited strings, their order does not matter,
67 | * and each string adds an additional access range to the
68 | * requested scope.
69 | *
70 | * @access public
71 | * @return void
72 | * @throw Oauthz_Exception_Token Error Codes: invalid_request
73 | */
74 | public function __construct($args = NULL)
75 | {
76 | isset($_SERVER['CONTENT_TYPE']) OR $_SERVER['CONTENT_TYPE'] = getenv('CONTENT_TYPE');
77 |
78 | // Parse the "state" paramter
79 | if(isset($_POST['state']))
80 | {
81 | if($state = rawurldecode($_POST['state']))
82 | $this->state['state'] = $state;
83 |
84 | unset($args['state']);
85 | }
86 |
87 | // oauth_token already send in authorization header or the encrypt Content-Type is not single-part
88 | if(empty($_POST) OR stripos($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') === FALSE)
89 | {
90 | throw new Oauthz_Exception_Token('invalid_request');
91 | }
92 | else
93 | {
94 | // TODO move this request data detect into authorization handler
95 | if(isset($_SERVER['PHP_AUTH_USER']) AND isset($_SERVER['PHP_AUTH_PW']))
96 | {
97 | $_POST += array('username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']);
98 | }
99 | // TODO Digest HTTP authentication
100 | //else if( ! empty($_SERVER['PHP_AUTH_DIGEST']) AND $digest = parent::parse_digest($_SERVER['PHP_AUTH_DIGEST']))
101 | //{
102 | // $_POST += array('username' => $digest['username'], 'password' => $digest['']);
103 | //}
104 |
105 | // Check all required parameters from form-encoded body
106 | foreach($args as $key => $val)
107 | {
108 | if($val === TRUE)
109 | {
110 | if(isset($_POST[$key]) AND $value = rawurldecode($_POST[$key]))
111 | {
112 | $this->$key = $value;
113 | }
114 | else
115 | {
116 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
117 | }
118 | }
119 | }
120 | }
121 | }
122 |
123 | /**
124 | * Populate the access token thu the request info and client info stored in the server
125 | *
126 | * @access public
127 | * @param array $client
128 | * @return Oauthz_Token
129 | * @throw Oauthz_Exception_Token Error Codes: unauthorized_client, invalid_request, invalid_scope
130 | */
131 | public function execute()
132 | {
133 | if($client = Model_Oauthz::factory('Client')->lookup($this->client_id))
134 | {
135 | // Audit
136 | }
137 | else
138 | {
139 | // Invalid client_id
140 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
141 | }
142 |
143 | // TODO password should be hashed with much more stronger method
144 | if($client['client_secret'] !== sha1($this->client_secret)
145 | OR $client['username'] !== $this->username
146 | OR $client['password'] !== sha1($this->password)
147 | OR $client['redirect_uri'] !== $this->redirect_uri)
148 | {
149 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
150 | }
151 |
152 | if(isset($this->scope) AND ! empty($client['scope'])
153 | AND ! in_array($this->scope, explode(' ', $client['scope'])))
154 | {
155 | throw new Oauthz_Exception_Token('invalid_scope', $this->state);
156 | }
157 |
158 | if($client['expires_in'] < $_SERVER['REQUEST_TIME'])
159 | {
160 | $params = $this->state;
161 | $params['error_uri'] = $this->redirect_uri;
162 |
163 | throw new Oauthz_Exception_Access('invalid_grant', $params);
164 | }
165 |
166 | $token = new Oauthz_Token;
167 |
168 | // TODO: issue "mac" OAuth Access Token Type
169 | $token->token_type = $client['token_type'];
170 | $token->access_token = $client['access_token'];
171 | $token->refresh_token = $client['refresh_token'];
172 |
173 | // merge other token properties, e.g. {"mac_key":"adijq39jdlaska9asud","mac_algorithm":"hmac-sha-256"}
174 | if($client['options'] AND $option = json_decode($client['options'], TRUE))
175 | {
176 | foreach($option as $key => $val)
177 | {
178 | $token->$key = $val;
179 | }
180 | }
181 |
182 | isset($this->state['state']) AND $token->state = $this->state['state'];
183 |
184 | return $token;
185 | }
186 |
187 | } // END Oauthz_Extension_Password
188 |
--------------------------------------------------------------------------------
/doc/oauth-oracle.sql:
--------------------------------------------------------------------------------
1 | /**
2 | * OAuth database table schema for Oracle
3 | *
4 | * @author sumh <42424861@qq.com>
5 | * @package Oauth
6 | * @copyright (c) 2011 OALite
7 | * @license ISC License (ISCL)
8 | * @link http://oalite.com
9 | */
10 |
11 | /******************** Add Table: t_oauth_authorizes ************************/
12 |
13 | /* Build Table Structure */
14 | CREATE TABLE t_oauth_authorizes
15 | (
16 | user_id BIGINT NULL,
17 | client_id VARCHAR(127) NOT NULL,
18 | redirect_uri VARCHAR(511) NOT NULL,
19 | confirm_type TINYINT DEFAULT 0 NOT NULL,
20 | client_level TINYINT DEFAULT 0 NOT NULL,
21 | client_desc TEXT NULL,
22 | expires_in INTEGER NULL,
23 | scope VARCHAR(511) NULL,
24 | created INTEGER NOT NULL,
25 | modified INTEGER NULL,
26 | remark TEXT NULL
27 | ) DEFAULT CHARSET=utf8;
28 |
29 | /* Table Items: t_oauth_authorizes */
30 | ALTER TABLE t_oauth_authorizes ADD CONSTRAINT pkt_oauth_authorizes
31 | PRIMARY KEY (user_id);
32 |
33 | /* Set Comments */
34 | COMMENT ON COLUMN t_oauth_authorizes.confirm_type IS 'Request confirm, 0: every time; 1: only once; 2: with expired period; 3: once and banned';
35 | COMMENT ON COLUMN t_oauth_authorizes.client_level IS 'diferent client levels have different max request times';
36 | COMMENT ON COLUMN t_oauth_authorizes.expires_in IS 'date time';
37 | COMMENT ON TABLE t_oauth_authorizes IS 'Store audit information from resource owner for the resource requester';
38 |
39 | /******************** Add Table: t_oauth_clients ************************/
40 |
41 | /* Build Table Structure */
42 | CREATE TABLE t_oauth_clients
43 | (
44 | server_id BIGINT NOT NULL,
45 | client_id VARCHAR(127) NOT NULL,
46 | client_secret VARCHAR(127) NOT NULL,
47 | redirect_uri VARCHAR(511) NOT NULL,
48 | scope VARCHAR(255) NULL,
49 | secret_type ENUM('plaintext','md5','rsa-sha1','hmac-sha1') DEFAULT 'plaintext' NOT NULL,
50 | ssh_key VARCHAR(511) NULL,
51 | app_name VARCHAR(127) NOT NULL,
52 | app_desc TEXT NULL,
53 | app_profile ENUM('webserver','native','useragent','autonomous') DEFAULT 'webserver' NOT NULL,
54 | app_purpose VARCHAR(511) NULL,
55 | user_id BIGINT NULL,
56 | user_level TINYINT DEFAULT 0 NOT NULL,
57 | enabled TINYINT DEFAULT 1 NOT NULL,
58 | created INTEGER NOT NULL,
59 | modified INTEGER NULL
60 | ) DEFAULT CHARSET=utf8;
61 |
62 | /* Table Items: t_oauth_clients */
63 | ALTER TABLE t_oauth_clients ADD CONSTRAINT pkt_oauth_clients
64 | PRIMARY KEY (server_id);
65 |
66 | /* Set Comments */
67 | COMMENT ON COLUMN t_oauth_clients.client_id IS 'AKA. API key';
68 | COMMENT ON COLUMN t_oauth_clients.client_secret IS 'AKA. API secret';
69 | COMMENT ON COLUMN t_oauth_clients.redirect_uri IS 'AKA. Callback URI';
70 | COMMENT ON COLUMN t_oauth_clients.scope IS 'May be create, read, update or delete. so on so for';
71 | COMMENT ON COLUMN t_oauth_clients.secret_type IS 'Secret signature encrypt type. e.g';
72 | COMMENT ON COLUMN t_oauth_clients.ssh_key IS 'SSH public keys';
73 | COMMENT ON COLUMN t_oauth_clients.app_name IS 'Application Name';
74 | COMMENT ON COLUMN t_oauth_clients.app_desc IS 'Application Description, When users authenticate via your app, this is what they''ll see.';
75 | COMMENT ON COLUMN t_oauth_clients.app_profile IS 'Application Profile: Web Server Application, Native Application, Browser Application, Autonomous clients';
76 | COMMENT ON COLUMN t_oauth_clients.user_id IS 'Ref# from users table';
77 | COMMENT ON COLUMN t_oauth_clients.user_level IS 'diferent client levels have different max request times';
78 | COMMENT ON COLUMN t_oauth_clients.enabled IS '0: waiting for system administrator audit; 1: acceptable; 2: ban';
79 | COMMENT ON COLUMN t_oauth_clients.created IS 'create datetime';
80 | COMMENT ON COLUMN t_oauth_clients.modified IS 'modified datetime';
81 | COMMENT ON TABLE t_oauth_clients IS 'Used for verification of incoming requests. ';
82 |
83 | /* Add Indexes for: t_oauth_clients */
84 | CREATE UNIQUE INDEX idx_t_oauth_clients_client_id ON t_oauth_clients (client_id);
85 |
86 | /******************** Add Table: t_oauth_logs ************************/
87 |
88 | /* Build Table Structure */
89 | CREATE TABLE t_oauth_logs
90 | (
91 | log_id BIGINT NOT NULL,
92 | client_id VARCHAR(127) NULL,
93 | token VARCHAR(63) NULL,
94 | user_id BIGINT NULL,
95 | received TEXT NOT NULL,
96 | sent TEXT NOT NULL,
97 | body TEXT NOT NULL,
98 | notes TEXT NOT NULL,
99 | "timestamp" TIMESTAMP NOT NULL,
100 | remote_ip BIGINT NOT NULL
101 | ) DEFAULT CHARSET=utf8;
102 |
103 | /* Table Items: t_oauth_logs */
104 | ALTER TABLE t_oauth_logs ADD CONSTRAINT pkt_oauth_logs
105 | PRIMARY KEY (log_id);
106 |
107 | /* Set Comments */
108 | COMMENT ON TABLE t_oauth_logs IS 'Log table to hold all OAuth request when you enabled logging ';
109 |
110 | /* Add Indexes for: t_oauth_logs */
111 | CREATE INDEX idx_t_oauth_logs_client_id_log_id ON t_oauth_logs (client_id, log_id);
112 |
113 | /******************** Add Table: t_oauth_tokens ************************/
114 |
115 | /* Build Table Structure */
116 | CREATE TABLE t_oauth_tokens
117 | (
118 | token_id BIGINT NOT NULL,
119 | client_id VARCHAR(127) NOT NULL,
120 | user_id BIGINT NOT NULL,
121 | code VARCHAR(127) NOT NULL,
122 | access_token VARCHAR(63) NULL,
123 | refresh_token VARCHAR(63) NULL,
124 | expire_code INTEGER DEFAULT 300 NOT NULL,
125 | expire_token INTEGER DEFAULT 0 NOT NULL,
126 | expire_refresh INTEGER DEFAULT 0 NOT NULL,
127 | "timestamp" INTEGER NOT NULL,
128 | token_type VARCHAR(127) NOT NULL,
129 | options TEXT NULL
130 | ) DEFAULT CHARSET=utf8;
131 |
132 | /* Table Items: t_oauth_tokens */
133 | ALTER TABLE t_oauth_tokens ADD CONSTRAINT pkt_oauth_tokens
134 | PRIMARY KEY (token_id);
135 |
136 | /* Set Comments */
137 | COMMENT ON COLUMN t_oauth_tokens.user_id IS 'Ref# from users table';
138 | COMMENT ON COLUMN t_oauth_tokens.expire_code IS 'authorization code expires in this timestamp';
139 | COMMENT ON COLUMN t_oauth_tokens.expire_token IS 'access token expires in this timestamp';
140 | COMMENT ON COLUMN t_oauth_tokens.expire_refresh IS 'refresh token expires in this timestamp';
141 | COMMENT ON COLUMN t_oauth_tokens."timestamp" IS 'authorization code request timestamp';
142 | COMMENT ON COLUMN t_oauth_tokens.token_type IS 'bearer, mac, etc.';
143 | COMMENT ON COLUMN t_oauth_tokens.options IS 'parameters for different token type extension in json format';
144 | COMMENT ON TABLE t_oauth_tokens IS 'Table used to verify signed requests sent to a server by the consumer.When the verification is succesful then the associated user id is returned. ';
145 |
146 | /* Add Indexes for: t_oauth_tokens */
147 | CREATE INDEX idx_t_oauth_tokens_access_token ON t_oauth_tokens (access_token);
148 | CREATE INDEX idx_t_oauth_tokens_client_id ON t_oauth_tokens (client_id);
149 | CREATE INDEX idx_t_oauth_tokens_code ON t_oauth_tokens (code);
150 | CREATE INDEX idx_t_oauth_tokens_refresh_token ON t_oauth_tokens (refresh_token);
151 |
152 |
153 | /************ Add Foreign Keys to Database ***************/
154 |
155 | /************ Foreign Key: fk_t_oauth_tokens_t_oauth_clients ***************/
156 | ALTER TABLE t_oauth_tokens ADD CONSTRAINT fk_t_oauth_tokens_t_oauth_clients
157 | FOREIGN KEY (client_id) REFERENCES t_oauth_clients (client_id)
158 | ON DELETE CASCADE;
--------------------------------------------------------------------------------
/doc/oauth-postgresql.sql:
--------------------------------------------------------------------------------
1 | /**
2 | * OAuth database table schema for PostgreSql
3 | *
4 | * @author sumh <42424861@qq.com>
5 | * @package Oauth
6 | * @copyright (c) 2011 OALite
7 | * @license ISC License (ISCL)
8 | * @link http://oalite.com
9 | */
10 |
11 | /******************** Add Table: "t_oauth_authorizes" ************************/
12 |
13 | /* Build Table Structure */
14 | CREATE TABLE "t_oauth_authorizes"
15 | (
16 | user_id BIGINT NULL,
17 | client_id VARCHAR(127) NOT NULL,
18 | redirect_uri VARCHAR(511) NOT NULL,
19 | confirm_type SMALLINT DEFAULT 0 NOT NULL,
20 | client_level SMALLINT DEFAULT 0 NOT NULL,
21 | client_desc TEXT NULL,
22 | expires_in INTEGER NULL,
23 | scope VARCHAR(511) NULL,
24 | created INTEGER NOT NULL,
25 | modified INTEGER NULL,
26 | remark TEXT NULL
27 | ) DEFAULT CHARSET=utf8;
28 |
29 | /* Table Items: "t_oauth_authorizes" */
30 | ALTER TABLE "t_oauth_authorizes" ADD CONSTRAINT pkt_oauth_authorizes
31 | PRIMARY KEY (user_id);
32 |
33 | /* Set Comments */
34 | COMMENT ON COLUMN "t_oauth_authorizes".confirm_type IS 'Request confirm, 0: every time; 1: only once; 2: with expired period; 3: once and banned';
35 | COMMENT ON COLUMN "t_oauth_authorizes".client_level IS 'diferent client levels have different max request times';
36 | COMMENT ON COLUMN "t_oauth_authorizes".expires_in IS 'date time';
37 | COMMENT ON TABLE "t_oauth_authorizes" IS 'Store audit information from resource owner for the resource requester';
38 |
39 | /******************** Add Table: "t_oauth_clients" ************************/
40 | CREATE SEQUENCE seq_t_oauth_clients_server_id INCREMENT BY 1;
41 |
42 | /* Build Table Structure */
43 | CREATE TABLE "t_oauth_clients"
44 | (
45 | server_id BIGINT NOT NULL DEFAULT nextval('seq_t_oauth_clients_server_id'),
46 | client_id VARCHAR(127) NOT NULL,
47 | client_secret VARCHAR(127) NOT NULL,
48 | redirect_uri VARCHAR(511) NOT NULL,
49 | scope VARCHAR(255) NULL,
50 | secret_type ENUM('plaintext','md5','rsa-sha1','hmac-sha1') DEFAULT 'plaintext' NOT NULL,
51 | ssh_key VARCHAR(511) NULL,
52 | app_name VARCHAR(127) NOT NULL,
53 | app_desc TEXT NULL,
54 | app_profile ENUM('webserver','native','useragent','autonomous') DEFAULT 'webserver' NOT NULL,
55 | app_purpose VARCHAR(511) NULL,
56 | user_id BIGINT NULL,
57 | user_level SMALLINT DEFAULT 0 NOT NULL,
58 | enabled SMALLINT DEFAULT 1 NOT NULL,
59 | created INTEGER NOT NULL,
60 | modified INTEGER NULL
61 | ) DEFAULT CHARSET=utf8;
62 |
63 | /* Table Items: "t_oauth_clients" */
64 | ALTER TABLE "t_oauth_clients" ADD CONSTRAINT pkt_oauth_clients
65 | PRIMARY KEY (server_id);
66 |
67 | /* Set Comments */
68 | COMMENT ON COLUMN "t_oauth_clients".client_id IS 'AKA. API key';
69 | COMMENT ON COLUMN "t_oauth_clients".client_secret IS 'AKA. API secret';
70 | COMMENT ON COLUMN "t_oauth_clients".redirect_uri IS 'AKA. Callback URI';
71 | COMMENT ON COLUMN "t_oauth_clients".scope IS 'May be create, read, update or delete. so on so for';
72 | COMMENT ON COLUMN "t_oauth_clients".secret_type IS 'Secret signature encrypt type. e.g';
73 | COMMENT ON COLUMN "t_oauth_clients".ssh_key IS 'SSH public keys';
74 | COMMENT ON COLUMN "t_oauth_clients".app_name IS 'Application Name';
75 | COMMENT ON COLUMN "t_oauth_clients".app_desc IS 'Application Description, When users authenticate via your app, this is what they''ll see.';
76 | COMMENT ON COLUMN "t_oauth_clients".app_profile IS 'Application Profile: Web Server Application, Native Application, Browser Application, Autonomous clients';
77 | COMMENT ON COLUMN "t_oauth_clients".user_id IS 'Ref# from users table';
78 | COMMENT ON COLUMN "t_oauth_clients".user_level IS 'diferent client levels have different max request times';
79 | COMMENT ON COLUMN "t_oauth_clients".enabled IS '0: waiting for system administrator audit; 1: acceptable; 2: ban';
80 | COMMENT ON COLUMN "t_oauth_clients".created IS 'create datetime';
81 | COMMENT ON COLUMN "t_oauth_clients".modified IS 'modified datetime';
82 | COMMENT ON TABLE "t_oauth_clients" IS 'Used for verification of incoming requests. ';
83 |
84 | /* Add Indexes for: t_oauth_clients */
85 | CREATE UNIQUE INDEX idx_t_oauth_clients_client_id ON "t_oauth_clients" (client_id);
86 |
87 | /******************** Add Table: "t_oauth_logs" ************************/
88 | CREATE SEQUENCE seq_t_oauth_logs_log_id INCREMENT BY 1;
89 |
90 | /* Build Table Structure */
91 | CREATE TABLE "t_oauth_logs"
92 | (
93 | log_id BIGINT NOT NULL DEFAULT nextval('seq_t_oauth_logs_log_id'),
94 | client_id VARCHAR(127) NULL,
95 | token VARCHAR(63) NULL,
96 | user_id BIGINT NULL,
97 | received TEXT NOT NULL,
98 | sent TEXT NOT NULL,
99 | body TEXT NOT NULL,
100 | notes TEXT NOT NULL,
101 | "timestamp" TIMESTAMP NOT NULL,
102 | remote_ip BIGINT NOT NULL
103 | ) DEFAULT CHARSET=utf8;
104 |
105 | /* Table Items: "t_oauth_logs" */
106 | ALTER TABLE "t_oauth_logs" ADD CONSTRAINT pkt_oauth_logs
107 | PRIMARY KEY (log_id);
108 |
109 | /* Set Comments */
110 | COMMENT ON TABLE "t_oauth_logs" IS 'Log table to hold all OAuth request when you enabled logging ';
111 |
112 | /* Add Indexes for: t_oauth_logs */
113 | CREATE INDEX idx_t_oauth_logs_client_id_log_id ON "t_oauth_logs" (client_id, log_id);
114 |
115 | /******************** Add Table: "t_oauth_tokens" ************************/
116 | CREATE SEQUENCE seq_t_oauth_tokens_token_id INCREMENT BY 1;
117 |
118 | /* Build Table Structure */
119 | CREATE TABLE "t_oauth_tokens"
120 | (
121 | token_id BIGINT NOT NULL DEFAULT nextval('seq_t_oauth_tokens_token_id'),
122 | client_id VARCHAR(127) NOT NULL,
123 | user_id BIGINT NOT NULL,
124 | code VARCHAR(127) NOT NULL,
125 | access_token VARCHAR(63) NULL,
126 | refresh_token VARCHAR(63) NULL,
127 | expire_code INTEGER DEFAULT 300 NOT NULL,
128 | expire_token INTEGER DEFAULT 0 NOT NULL,
129 | expire_refresh INTEGER DEFAULT 0 NOT NULL,
130 | "timestamp" INTEGER NOT NULL,
131 | token_type VARCHAR(127) NOT NULL,
132 | options TEXT NULL
133 | ) DEFAULT CHARSET=utf8;
134 |
135 | /* Table Items: "t_oauth_tokens" */
136 | ALTER TABLE "t_oauth_tokens" ADD CONSTRAINT pkt_oauth_tokens
137 | PRIMARY KEY (token_id);
138 |
139 | /* Set Comments */
140 | COMMENT ON COLUMN "t_oauth_tokens".user_id IS 'Ref# from users table';
141 | COMMENT ON COLUMN "t_oauth_tokens".expire_code IS 'authorization code expires in this timestamp';
142 | COMMENT ON COLUMN "t_oauth_tokens".expire_token IS 'access token expires in this timestamp';
143 | COMMENT ON COLUMN "t_oauth_tokens".expire_refresh IS 'refresh token expires in this timestamp';
144 | COMMENT ON COLUMN "t_oauth_tokens"."timestamp" IS 'authorization code request timestamp';
145 | COMMENT ON COLUMN "t_oauth_tokens".token_type IS 'bearer, mac, etc.';
146 | COMMENT ON COLUMN "t_oauth_tokens".options IS 'parameters for different token type extension in json format';
147 | COMMENT ON TABLE "t_oauth_tokens" IS 'Table used to verify signed requests sent to a server by the consumer.When the verification is succesful then the associated user id is returned. ';
148 |
149 | /* Add Indexes for: t_oauth_tokens */
150 | CREATE INDEX idx_t_oauth_tokens_access_token ON "t_oauth_tokens" (access_token);
151 | CREATE INDEX idx_t_oauth_tokens_client_id ON "t_oauth_tokens" (client_id);
152 | CREATE INDEX idx_t_oauth_tokens_code ON "t_oauth_tokens" (code);
153 | CREATE INDEX idx_t_oauth_tokens_refresh_token ON "t_oauth_tokens" (refresh_token);
154 |
155 |
156 | /************ Add Foreign Keys to Database ***************/
157 |
158 | /************ Foreign Key: fk_t_oauth_tokens_t_oauth_clients ***************/
159 | ALTER TABLE "t_oauth_tokens" ADD CONSTRAINT fk_t_oauth_tokens_t_oauth_clients
160 | FOREIGN KEY (client_id) REFERENCES "t_oauth_clients" (client_id)
161 | ON UPDATE CASCADE ON DELETE CASCADE;
--------------------------------------------------------------------------------
/classes/model/oauthz/authorize.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Model_Oauthz
11 | * *
12 | */
13 | class Model_Oauthz_Authorize extends Model_Oauthz {
14 |
15 | public function get($user_id)
16 | {
17 | return ctype_digit((string) $user_id)
18 | ? DB::select('user_id','client_id','redirect_uri','confirm_type','client_level','modified','created','scope','expired_date','remark','client_desc')
19 | ->from('t_oauth_authorizes')
20 | ->where('user_id', '=', $user_id)
21 | ->execute($this->_db)
22 | ->current()
23 | : NULL;
24 | }
25 |
26 | /**
27 | * Insert authorize
28 | *
29 | * @access public
30 | * @param array $params
31 | * confirm_type: Request confirm, 0: every time; 1: only once; 2: with expired period; 3: once and banned
32 | * client_level: diferent authorize levels have different max request times
33 | * expired_date: date time
34 | *
35 | * @return mix array(insert_id, affect_rows) or validate object
36 | */
37 | public function append(array $params)
38 | {
39 | if(isset($params['expired_date']) AND $timetamp = strtotime($params['expired_date']))
40 | $params['expired_date'] = $timetamp;
41 | else
42 | unset($params['expired_date']);
43 |
44 | $valid = Validate::factory($params)
45 | ->rule('client_id', 'not_empty')
46 | ->rule('redirect_uri', 'not_empty')
47 | ->rule('modified', 'not_empty');
48 |
49 | $rules = array_intersect_key(array (
50 | 'client_id' => array ('max_length' => array (128)),
51 | 'redirect_uri' => array ('max_length' => array (512)),
52 | 'confirm_type' => array ('range' => array (0,255)),
53 | 'client_level' => array ('range' => array (0,255)),
54 | 'scope' => array ('max_length' => array (512)),
55 | 'expired_date' => array ('range' => array (0,4294967295)),
56 | 'client_desc' => array ('max_length' => array (65535)),
57 | ), $params);
58 |
59 | foreach($rules as $field => $rule)
60 | foreach($rule as $r => $p)
61 | $valid->rule($field, $r, $p);
62 |
63 | if($valid->check())
64 | {
65 | $valid = $valid->as_array();
66 |
67 | foreach($valid as $key => $val)
68 | {
69 | if($val === '') $valid[$key] = NULL;
70 | }
71 |
72 | $valid['created'] = $_SERVER['REQUEST_TIME'];
73 |
74 | return DB::insert('t_oauth_authorizes', array_keys($valid))
75 | ->values(array_values($valid))
76 | ->execute($this->_db);
77 | }
78 | else
79 | {
80 | // Validation failed, collect the errors
81 | return $valid;
82 | }
83 | }
84 |
85 | /**
86 | * Update client
87 | *
88 | * @access public
89 | * @param int $user_id
90 | * @param array $params
91 | * confirm_type: Request confirm, 0: every time; 1: only once; 2: with expired period; 3: once and banned
92 | * client_level: diferent client levels have different max request times
93 | * expired_date: date time
94 | *
95 | * @return mix update rows affect or validate object
96 | */
97 | public function update($user_id, array $params)
98 | {
99 | if(isset($params['expired_date']) AND $timetamp = strtotime($params['expired_date']))
100 | $params['expired_date'] = $timetamp;
101 | else
102 | unset($params['expired_date']);
103 |
104 | $valid = Validate::factory($params);
105 |
106 | $rules = array_intersect_key(array (
107 | 'client_id' => array ('not_empty' => NULL, 'max_length' => array (128)),
108 | 'redirect_uri' => array ('not_empty' => NULL, 'max_length' => array (512)),
109 | 'confirm_type' => array ('range' => array (0,255)),
110 | 'client_level' => array ('range' => array (0,255)),
111 | 'scope' => array ('max_length' => array (512)),
112 | 'expired_date' => array ('range' => array (0,4294967295)),
113 | 'client_desc' => array ('max_length' => array (65535)),
114 | ), $params);
115 |
116 | foreach($rules as $field => $rule)
117 | foreach($rule as $r => $p)
118 | $valid->rule($field, $r, $p);
119 |
120 | if($valid->check())
121 | {
122 | $valid = $valid->as_array();
123 |
124 | foreach($valid as $key => $val)
125 | {
126 | if($val === '') $valid[$key] = NULL;
127 | }
128 |
129 | $valid['modifed'] = $_SERVER['REQUEST_TIME'];
130 |
131 | return DB::update('t_oauth_authorizes')
132 | ->set($valid)
133 | ->where('user_id', '=', $user_id)
134 | ->execute($this->_db);
135 | }
136 | else
137 | {
138 | // Validation failed, collect the errors
139 | return $valid;
140 | }
141 | }
142 |
143 | public function delete($client_id, $user_id)
144 | {
145 | return ctype_digit((string) $user_id)
146 | ? DB::delete('t_oauth_authorizes')
147 | ->where('client_id', '=', $client_id)
148 | ->where('user_id', '=', $user_id)
149 | ->execute($this->_db)
150 | : NULL;
151 | }
152 |
153 | /**
154 | * List clients
155 | *
156 | * @access public
157 | * @param array $params
158 | * @param Pagination $pagination default [ NULL ] passed by reference
159 | * @param boolean $calc_total default [ TRUE ] is needed to caculate the total records for pagination
160 | * @return array array('clients' => data, 'orderby' => $params['orderby'], 'pagination' => $pagination)
161 | */
162 | public function lists(array $params, $pagination = NULL, $calc_total = TRUE)
163 | {
164 | $pagination instanceOf Pagination OR $pagination = new Pagination;
165 |
166 | $sql = 'FROM `t_oauth_authorizes` ';
167 |
168 | // Customize where from params
169 | //$sql .= 'WHERE ... '
170 |
171 | // caculte the total rows
172 | if($calc_total === TRUE)
173 | {
174 | $pagination->total_items = $this->_db->query(
175 | Database::SELECT, 'SELECT COUNT(`user_id`) num_rows '.$sql, FALSE
176 | )->get('num_rows');
177 |
178 | $data['pagination'] = $pagination;
179 |
180 | if($pagination->total_items === 0)
181 | {
182 | $data['clients'] = array();
183 | isset($params['orderby']) AND $data['orderby'] = $params['orderby'];
184 | return $data;
185 | }
186 | }
187 |
188 | // Customize order by from params
189 | if(isset($params['orderby']))
190 | {
191 | switch($params['orderby'])
192 | {
193 | case 'level':
194 | $sql .= ' ORDER BY client_level DESC';
195 | break;
196 | case 'expired':
197 | $sql .= ' ORDER BY expired_date DESC';
198 | break;
199 | case 'update':
200 | $sql .= ' ORDER BY modified DESC';
201 | break;
202 | default:
203 | $params['orderby'] = 'client';
204 | $sql .= ' ORDER BY client_id DESC';
205 | break;
206 | }
207 | $data['orderby'] = $params['orderby'];
208 | }
209 |
210 | $sql .= " LIMIT {$pagination->offset}, {$pagination->items_per_page}";
211 |
212 | $data['clients'] = $this->_db->query(Database::SELECT, 'SELECT * '.$sql, FALSE);
213 |
214 | return $data;
215 | }
216 |
217 | } // END Model_Oauthz_Authorize
218 |
--------------------------------------------------------------------------------
/doc/oauth-mssql.sql:
--------------------------------------------------------------------------------
1 | /**
2 | * OAuth database table schema for MSSQL
3 | *
4 | * @author sumh <42424861@qq.com>
5 | * @package Oauth
6 | * @copyright (c) 2011 OALite
7 | * @license ISC License (ISCL)
8 | * @link http://oalite.com
9 | */
10 |
11 | /******************** Add Table: t_oauth_authorizes ************************/
12 |
13 | /* Build Table Structure */
14 | CREATE TABLE Server.t_oauth_authorizes
15 | (
16 | user_id BIGINT NULL,
17 | client_id VARCHAR(127) NOT NULL,
18 | redirect_uri VARCHAR(511) NOT NULL,
19 | confirm_type TINYINT DEFAULT 0 NOT NULL,
20 | client_level TINYINT DEFAULT 0 NOT NULL,
21 | client_desc TEXT NULL,
22 | expires_in INTEGER NULL,
23 | scope VARCHAR(511) NULL,
24 | created INTEGER NOT NULL,
25 | modified INTEGER NULL,
26 | remark TEXT NULL
27 | ) DEFAULT CHARSET=utf8;
28 |
29 | /* Table Items: Server.t_oauth_authorizes */
30 | ALTER TABLE Server.t_oauth_authorizes ADD CONSTRAINT pkt_oauth_authorizes
31 | PRIMARY KEY (user_id);
32 |
33 | /* Set Comments */
34 | EXEC sp_addextendedproperty 'MS_Description', 'Request confirm, 0: every time; 1: only once; 2: with expired period; 3: once and banned',
35 | 'table', 't_oauth_authorizes', 'column', 'confirm_type';
36 | EXEC sp_addextendedproperty 'MS_Description', 'diferent client levels have different max request times',
37 | 'table', 't_oauth_authorizes', 'column', 'client_level';
38 | EXEC sp_addextendedproperty 'MS_Description', 'date time',
39 | 'table', 't_oauth_authorizes', 'column', 'expires_in';
40 | EXEC sp_addextendedproperty 'MS_Description', 'Store audit information from resource owner for the resource requester',
41 | 'table', t_oauth_authorizes, null, null;
42 |
43 | /******************** Add Table: Server.t_oauth_clients ************************/
44 |
45 | /* Build Table Structure */
46 | CREATE TABLE Server.t_oauth_clients
47 | (
48 | server_id BIGINT IDENTITY (1, 1) NOT NULL,
49 | client_id VARCHAR(127) NOT NULL,
50 | client_secret VARCHAR(127) NOT NULL,
51 | redirect_uri VARCHAR(511) NOT NULL,
52 | scope VARCHAR(255) NULL,
53 | secret_type ENUM('plaintext','md5','rsa-sha1','hmac-sha1') DEFAULT 'plaintext' NOT NULL,
54 | ssh_key VARCHAR(511) NULL,
55 | app_name VARCHAR(127) NOT NULL,
56 | app_desc TEXT NULL,
57 | app_profile ENUM('webserver','native','useragent','autonomous') DEFAULT 'webserver' NOT NULL,
58 | app_purpose VARCHAR(511) NULL,
59 | user_id BIGINT NULL,
60 | user_level TINYINT DEFAULT 0 NOT NULL,
61 | enabled TINYINT DEFAULT 1 NOT NULL,
62 | created INTEGER NOT NULL,
63 | modified INTEGER NULL
64 | ) DEFAULT CHARSET=utf8;
65 |
66 | /* Table Items: Server.t_oauth_clients */
67 | ALTER TABLE Server.t_oauth_clients ADD CONSTRAINT pkt_oauth_clients
68 | PRIMARY KEY (server_id);
69 |
70 | /* Set Comments */
71 | EXEC sp_addextendedproperty 'MS_Description', 'AKA. API key',
72 | 'table', 't_oauth_clients', 'column', 'client_id';
73 | EXEC sp_addextendedproperty 'MS_Description', 'AKA. API secret',
74 | 'table', 't_oauth_clients', 'column', 'client_secret';
75 | EXEC sp_addextendedproperty 'MS_Description', 'AKA. Callback URI',
76 | 'table', 't_oauth_clients', 'column', 'redirect_uri';
77 | EXEC sp_addextendedproperty 'MS_Description', 'May be create, read, update or delete. so on so for',
78 | 'table', 't_oauth_clients', 'column', 'scope';
79 | EXEC sp_addextendedproperty 'MS_Description', 'Secret signature encrypt type. e.g',
80 | 'table', 't_oauth_clients', 'column', 'secret_type';
81 | EXEC sp_addextendedproperty 'MS_Description', 'SSH public keys',
82 | 'table', 't_oauth_clients', 'column', 'ssh_key';
83 | EXEC sp_addextendedproperty 'MS_Description', 'Application Name',
84 | 'table', 't_oauth_clients', 'column', 'app_name';
85 | EXEC sp_addextendedproperty 'MS_Description', 'Application Description, When users authenticate via your app, this is what they''ll see.',
86 | 'table', 't_oauth_clients', 'column', 'app_desc';
87 | EXEC sp_addextendedproperty 'MS_Description', 'Application Profile: Web Server Application, Native Application, Browser Application, Autonomous clients',
88 | 'table', 't_oauth_clients', 'column', 'app_profile';
89 | EXEC sp_addextendedproperty 'MS_Description', 'Ref# from users table',
90 | 'table', 't_oauth_clients', 'column', 'user_id';
91 | EXEC sp_addextendedproperty 'MS_Description', 'diferent client levels have different max request times',
92 | 'table', 't_oauth_clients', 'column', 'user_level';
93 | EXEC sp_addextendedproperty 'MS_Description', '0: waiting for system administrator audit; 1: acceptable; 2: ban',
94 | 'table', 't_oauth_clients', 'column', 'enabled';
95 | EXEC sp_addextendedproperty 'MS_Description', 'create datetime',
96 | 'table', 't_oauth_clients', 'column', 'created';
97 | EXEC sp_addextendedproperty 'MS_Description', 'modified datetime',
98 | 'table', 't_oauth_clients', 'column', 'modified';
99 | EXEC sp_addextendedproperty 'MS_Description', 'Used for verification of incoming requests. ',
100 | 'table', t_oauth_clients, null, null;
101 |
102 | /* Add Indexes for: t_oauth_clients */
103 | CREATE UNIQUE NONCLUSTERED INDEX idx_t_oauth_clients_client_id ON Server.t_oauth_clients (client_id);
104 |
105 | /******************** Add Table: Server.t_oauth_logs ************************/
106 |
107 | /* Build Table Structure */
108 | CREATE TABLE Server.t_oauth_logs
109 | (
110 | log_id BIGINT IDENTITY (1, 1) NOT NULL,
111 | client_id VARCHAR(127) NULL,
112 | token VARCHAR(63) NULL,
113 | user_id BIGINT NULL,
114 | received TEXT NOT NULL,
115 | sent TEXT NOT NULL,
116 | body TEXT NOT NULL,
117 | notes TEXT NOT NULL,
118 | [timestamp] TIMESTAMP NOT NULL,
119 | remote_ip BIGINT NOT NULL
120 | ) DEFAULT CHARSET=utf8;
121 |
122 | /* Table Items: Server.t_oauth_logs */
123 | ALTER TABLE Server.t_oauth_logs ADD CONSTRAINT pkt_oauth_logs
124 | PRIMARY KEY (log_id);
125 |
126 | /* Set Comments */
127 | EXEC sp_addextendedproperty 'MS_Description', 'Log table to hold all OAuth request when you enabled logging ',
128 | 'table', t_oauth_logs, null, null;
129 |
130 | /* Add Indexes for: t_oauth_logs */
131 | CREATE NONCLUSTERED INDEX idx_t_oauth_logs_client_id_log_id ON Server.t_oauth_logs (client_id, log_id);
132 |
133 | /******************** Add Table: Server.t_oauth_tokens ************************/
134 |
135 | /* Build Table Structure */
136 | CREATE TABLE Server.t_oauth_tokens
137 | (
138 | token_id BIGINT IDENTITY (1, 1) NOT NULL,
139 | client_id VARCHAR(127) NOT NULL,
140 | user_id BIGINT NOT NULL,
141 | code VARCHAR(127) NOT NULL,
142 | access_token VARCHAR(63) NULL,
143 | refresh_token VARCHAR(63) NULL,
144 | expire_code INTEGER DEFAULT 300 NOT NULL,
145 | expire_token INTEGER DEFAULT 0 NOT NULL,
146 | expire_refresh INTEGER DEFAULT 0 NOT NULL,
147 | [timestamp] INTEGER NOT NULL,
148 | token_type VARCHAR(127) NOT NULL,
149 | options TEXT NULL
150 | ) DEFAULT CHARSET=utf8;
151 |
152 | /* Table Items: Server.t_oauth_tokens */
153 | ALTER TABLE Server.t_oauth_tokens ADD CONSTRAINT pkt_oauth_tokens
154 | PRIMARY KEY (token_id);
155 |
156 | /* Set Comments */
157 | EXEC sp_addextendedproperty 'MS_Description', 'Ref# from users table',
158 | 'table', 't_oauth_tokens', 'column', 'user_id';
159 | EXEC sp_addextendedproperty 'MS_Description', 'authorization code expires in this timestamp',
160 | 'table', 't_oauth_tokens', 'column', 'expire_code';
161 | EXEC sp_addextendedproperty 'MS_Description', 'access token expires in this timestamp',
162 | 'table', 't_oauth_tokens', 'column', 'expire_token';
163 | EXEC sp_addextendedproperty 'MS_Description', 'refresh token expires in this timestamp',
164 | 'table', 't_oauth_tokens', 'column', 'expire_refresh';
165 | EXEC sp_addextendedproperty 'MS_Description', 'authorization code request timestamp',
166 | 'table', 't_oauth_tokens', 'column', 'timestamp';
167 | EXEC sp_addextendedproperty 'MS_Description', 'bearer, mac, etc.',
168 | 'table', 't_oauth_tokens', 'column', 'token_type';
169 | EXEC sp_addextendedproperty 'MS_Description', 'parameters for different token type extension in json format',
170 | 'table', 't_oauth_tokens', 'column', 'options';
171 | EXEC sp_addextendedproperty 'MS_Description', 'Table used to verify signed requests sent to a server by the consumer.When the verification is succesful then the associated user id is returned. ',
172 | 'table', t_oauth_tokens, null, null;
173 |
174 | /* Add Indexes for: t_oauth_tokens */
175 | CREATE NONCLUSTERED INDEX idx_t_oauth_tokens_access_token ON Server.t_oauth_tokens (access_token);
176 | CREATE NONCLUSTERED INDEX idx_t_oauth_tokens_client_id ON Server.t_oauth_tokens (client_id);
177 | CREATE NONCLUSTERED INDEX idx_t_oauth_tokens_code ON Server.t_oauth_tokens (code);
178 | CREATE NONCLUSTERED INDEX idx_t_oauth_tokens_refresh_token ON Server.t_oauth_tokens (refresh_token);
179 |
180 | /************ Add Foreign Keys to Database ***************/
181 |
182 | /************ Foreign Key: fk_t_oauth_tokens_t_oauth_clients ***************/
183 | ALTER TABLE Server.t_oauth_tokens ADD CONSTRAINT fk_t_oauth_tokens_t_oauth_clients
184 | FOREIGN KEY (client_id) REFERENCES Server.t_oauth_clients (client_id)
185 | ON UPDATE CASCADE ON DELETE CASCADE;
--------------------------------------------------------------------------------
/classes/model/oauthz/token.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Model_Oauthz
11 | * *
12 | */
13 | class Model_Oauthz_Token extends Model_Oauthz {
14 |
15 | public function get($token_id)
16 | {
17 | return ctype_digit((string) $token_id)
18 | ? DB::select('*')
19 | ->from('t_oauth_tokens')
20 | ->where('token_id', '=', $token_id)
21 | ->execute($this->_db)
22 | ->current()
23 | : NULL;
24 | }
25 |
26 | /**
27 | * Insert token
28 | *
29 | * @access public
30 | * @param array $params
31 | * user_id: Ref# from users table
32 | *
33 | * @return array token
34 | */
35 | public function code($client_id, $token_type, $expires_in = 120, array $options = NULL)
36 | {
37 | if($client_id AND $client = DB::select('client_secret','server_id','redirect_uri','user_id')
38 | ->from('t_oauth_clients')
39 | ->where('client_id' , '=', $client_id)
40 | ->where('enabled' , '=', 1)
41 | ->execute($this->_db)
42 | ->current())
43 | {
44 | // Initial code, access_token, refresh_token at the same time
45 | $client['code'] = uniqid();
46 | $client['expires_in'] = $_SERVER['REQUEST_TIME'] + $expires_in;
47 |
48 | isset($options) AND $options = json_encode($options);
49 |
50 | DB::insert('t_oauth_tokens', array(
51 | 'client_id',
52 | 'code',
53 | 'user_id',
54 | 'timestamp',
55 | 'expire_code',
56 | 'token_type',
57 | 'options'
58 | ))
59 | ->values(array(
60 | $client_id,
61 | $client['code'],
62 | 0, // TODO the user_id should be the resource owner
63 | $_SERVER['REQUEST_TIME'],
64 | $client['expires_in'],
65 | $token_type,
66 | $options
67 | ))
68 | ->execute($this->_db);
69 |
70 | $client['token_type'] = $token_type;
71 |
72 | return $client;
73 | }
74 |
75 | return NULL;
76 | }
77 |
78 | /**
79 | * Get the access_token and expire authorization_code
80 | *
81 | * @access public
82 | * @param string $client_id
83 | * @param string $code
84 | * @param int $expires_in default [ 3600 ]
85 | * @return mix
86 | */
87 | public function token($client_id, $code, $expires_in = 3600)
88 | {
89 | if($client = DB::select('server_id','client_secret','redirect_uri','user_id')
90 | ->from('t_oauth_clients')
91 | ->where('client_id' , '=', $client_id)
92 | ->execute($this->_db)
93 | ->current())
94 | {
95 | if($token = DB::select('token_id','access_token','token_type','refresh_token'
96 | ,array('expire_token', 'expires_in'),'options','expire_code')
97 | ->from('t_oauth_tokens')
98 | ->where('client_id' , '=', $client_id)
99 | ->where('code' , '=', $code)
100 | ->execute($this->_db)
101 | ->current())
102 | {
103 | if($token['expire_code'] >= $_SERVER['REQUEST_TIME'])
104 | {
105 | // Start access_token expire time counter
106 | $token['expires_in'] = $_SERVER['REQUEST_TIME'] + $expires_in;
107 |
108 | // Generate access_token
109 | $token['access_token'] = sha1(md5($_SERVER['REQUEST_TIME']));
110 |
111 | // Generate refresh_token
112 | $token['refresh_token'] = sha1(sha1(mt_rand()));
113 |
114 | // Update the expire timestamp of access_token to newest AND expire the code
115 | DB::update('t_oauth_tokens')
116 | ->set(array(
117 | 'expire_code' => 0,
118 | 'expire_token' => $token['expires_in'],
119 | 'access_token' => $token['access_token'],
120 | 'refresh_token' => $token['refresh_token']
121 | ))
122 | ->where('token_id', '=', $token['token_id'])
123 | ->execute($this->_db);
124 |
125 | // Don't expose these
126 | unset($token['token_id'], $token['expire_code']);
127 |
128 | $client += $token;
129 | }
130 | elseif($token['expire_code'] == 0 AND $token['expires_in'] != 0)
131 | {
132 | // revoke all tokens previously issued based on that authorization code.
133 | DB::update('t_oauth_tokens')
134 | ->set(array(
135 | 'expire_code' => 0,
136 | 'expire_token' => 0,
137 | 'expire_refresh' => 0
138 | ))
139 | ->where('token_id', '=', $token['token_id'])
140 | ->execute($this->_db);
141 | }
142 | }
143 | }
144 |
145 | return isset($client['access_token']) ? $client : NULL;
146 | }
147 |
148 | public function access_token($token)
149 | {
150 | if($token = DB::select('access_token','token_type','refresh_token'
151 | ,array('expire_token', 'expires_in'),'options')
152 | ->from('t_oauth_tokens')
153 | ->where('access_token', '=', $token)
154 | ->execute($this->_db)
155 | ->current())
156 | {
157 | //
158 | }
159 |
160 | return $token;
161 | }
162 |
163 | // TODO
164 | public function refresh_token($client_id, $token)
165 | {
166 | if($token = DB::select('access_token','token_type','refresh_token'
167 | ,array('expire_token', 'expires_in'),'options')
168 | ->from('t_oauth_tokens')
169 | ->where('client_id' , '=', $client_id)
170 | ->where('token' , '=', $token)
171 | ->execute($this->_db)
172 | ->current())
173 | {
174 | //
175 | }
176 |
177 | return $token;
178 | }
179 |
180 | public function assertion($client_id)
181 | {
182 | // TODO
183 | }
184 |
185 | public function delete($token_id, $client_id)
186 | {
187 | return ctype_digit((string) $token_id)
188 | ? DB::delete('t_oauth_tokens')
189 | ->where('token_id', '=', $token_id)
190 | ->where('client_id', '=', $client_id)
191 | ->execute($this->_db)
192 | : NULL;
193 | }
194 |
195 | /**
196 | * List tokens
197 | *
198 | * @access public
199 | * @param array $params
200 | * @param Pagination $pagination default [ NULL ] passed by reference
201 | * @param boolean $calc_total default [ TRUE ] is needed to caculate the total records for pagination
202 | * @return array array('tokens' => data, 'orderby' => $params['orderby'], 'pagination' => $pagination)
203 | */
204 | public function lists(array $params, $pagination = NULL, $calc_total = TRUE)
205 | {
206 | $pagination instanceOf Pagination OR $pagination = new Pagination;
207 |
208 | $sql = 'FROM `t_oauth_tokens` ';
209 |
210 | // Customize where from params
211 | //$sql .= 'WHERE ... '
212 |
213 | // caculte the total rows
214 | if($calc_total === TRUE)
215 | {
216 | $pagination->total_items = $this->_db->query(
217 | Database::SELECT, 'SELECT COUNT(`token_id`) num_rows '.$sql, FALSE
218 | )->get('num_rows');
219 |
220 | $data['pagination'] = $pagination;
221 |
222 | if($pagination->total_items === 0)
223 | {
224 | $data['tokens'] = array();
225 | isset($params['orderby']) AND $data['orderby'] = $params['orderby'];
226 | return $data;
227 | }
228 | }
229 |
230 | // Customize order by from params
231 | if(isset($params['orderby']))
232 | {
233 | switch($params['orderby'])
234 | {
235 | case 'client':
236 | $sql .= ' ORDER BY client_id DESC';
237 | break;
238 | case 'user':
239 | $sql .= ' ORDER BY user_id DESC';
240 | break;
241 | default:
242 | $params['orderby'] = 'timestamp';
243 | $sql .= ' ORDER BY timestamp DESC';
244 | break;
245 | }
246 | $data['orderby'] = $params['orderby'];
247 | }
248 |
249 | $sql .= " LIMIT {$pagination->offset}, {$pagination->items_per_page}";
250 |
251 | $data['tokens'] = $this->_db->query(Database::SELECT, 'SELECT * '.$sql, FALSE);
252 |
253 | return $data;
254 | }
255 |
256 | } // END Model_Oauthz_Token
257 |
--------------------------------------------------------------------------------
/classes/oauthz/extension/token.php:
--------------------------------------------------------------------------------
1 |
8 | * @package Oauthz
9 | * @copyright (c) 2010 OALite
10 | * @license ISC License (ISCL)
11 | * @link http://oalite.com
12 | * @see Oauthz_Extension
13 | * *
14 | */
15 | class Oauthz_Extension_Token extends Oauthz_Extension {
16 |
17 | /**
18 | * REQUIRED
19 | *
20 | * @access public
21 | * @var string $oauth_token
22 | */
23 | public $oauth_token;
24 |
25 | /**
26 | * Load request parameters from Authorization header, URI-Query parameters, Form-Encoded Body
27 | *
28 | * @access public
29 | * @param array $args
30 | * @return void
31 | * @throw Oauthz_Exception_Token Error code: invalid_request
32 | */
33 | public function __construct(array $args)
34 | {
35 | $params = array();
36 | /**
37 | * TODO move this request data detect into authorization handler
38 | * Load oauth token from authorization header
39 | */
40 | if (isset($_SERVER['HTTP_AUTHORIZATION']) OR $_SERVER['HTTP_AUTHORIZATION'] = getenv('HTTP_AUTHORIZATION'))
41 | {
42 | $offset = 0;
43 | $pattern = '/([-_a-z]*)=(?:"([^"]+)"|([^\s,]+)|\'([^\']+)\')/';
44 | if(preg_match_all($pattern, $_SERVER['HTTP_AUTHORIZATION'], $matches, PREG_SET_ORDER))
45 | {
46 | foreach($matches as $match)
47 | {
48 | if($value = rawurldecode($match[2] ?: $match[3]))
49 | {
50 | $params[$match[1]] = $value;
51 | }
52 | }
53 | }
54 | // Replace the name of token to oauth_token
55 | if(isset($params['token']))
56 | {
57 | // Parse the "state" paramter
58 | if(isset($params['state']) AND $state = rawurldecode($params['state']))
59 | $this->state['state'] = $state;
60 |
61 | $params['oauth_token'] = $params['token'];
62 | unset($params['token'], $args['state']);
63 |
64 | // Check all required parameters should NOT be empty
65 | foreach($args as $key => $val)
66 | {
67 | if($val === TRUE)
68 | {
69 | if(empty($params[$key]))
70 | {
71 | throw new Oauthz_Exception_Authorize('invalid_request', $this->state);
72 | }
73 | else
74 | {
75 | $this->$key = $params[$key];
76 | }
77 | }
78 | elseif($val !== FALSE)
79 | {
80 | $this->$key = $val;
81 | }
82 | }
83 | }
84 |
85 | $this->method = 'HEADER';
86 | }
87 |
88 | /**
89 | * Load oauth_token from form-encoded body
90 | */
91 | if(isset($_POST['oauth_token']))
92 | {
93 | isset($_SERVER['CONTENT_TYPE']) OR $_SERVER['CONTENT_TYPE'] = getenv('CONTENT_TYPE');
94 |
95 | // Parse the "state" paramter
96 | if(isset($_POST['state']))
97 | {
98 | if($state = rawurldecode($_POST['state']))
99 | $this->state['state'] = $state;
100 |
101 | unset($args['state']);
102 | }
103 |
104 | // oauth_token already send in authorization header or the encrypt Content-Type is not single-part
105 | if(isset($params['oauth_token']) OR stripos($_SERVER['CONTENT_TYPE'], 'application/x-www-form-urlencoded') === FALSE)
106 | {
107 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
108 | }
109 | else
110 | {
111 | // TODO move this request data detect into authorization handler
112 | if(isset($_SERVER['PHP_AUTH_USER']) AND isset($_SERVER['PHP_AUTH_PW']))
113 | {
114 | $_POST += array('client_id' => $_SERVER['PHP_AUTH_USER'], 'client_secret' => $_SERVER['PHP_AUTH_PW']);
115 | }
116 | // TODO Digest HTTP authentication
117 | //else if( ! empty($_SERVER['PHP_AUTH_DIGEST']) AND $digest = parent::parse_digest($_SERVER['PHP_AUTH_DIGEST']))
118 | //{
119 | // $_POST += array('client_id' => $digest['username'], 'client_secret' => $digest['']);
120 | //}
121 |
122 | // Check all required parameters should NOT be empty
123 | foreach($args as $key => $val)
124 | {
125 | if($val === TRUE)
126 | {
127 | if(isset($_POST[$key]) AND $value = rawurldecode($_POST[$key]))
128 | {
129 | $this->$key = $value;
130 | }
131 | else
132 | {
133 | throw new Oauthz_Exception_Authorize('invalid_request', $this->state);
134 | }
135 | }
136 | elseif($val !== FALSE)
137 | {
138 | $this->$key = $val;
139 | }
140 | }
141 | }
142 |
143 | $this->method = 'POST';
144 | }
145 |
146 | /**
147 | * Load oauth_token from uri-query component
148 | */
149 | if(isset($_GET['oauth_token']))
150 | {
151 | // Parse the "state" paramter
152 | if(isset($_GET['state']))
153 | {
154 | if($state = rawurldecode($_GET['state']))
155 | $this->state['state'] = $state;
156 |
157 | unset($args['state']);
158 | }
159 |
160 | // oauth_token already send in authorization header or form-encoded body
161 | if(isset($params['oauth_token']))
162 | {
163 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
164 | }
165 | else
166 | {
167 | // Check all required parameters should NOT be empty
168 | foreach($args as $key => $val)
169 | {
170 | if($val === TRUE)
171 | {
172 | if(isset($_GET[$key]) AND $value = rawurldecode($_GET[$key]))
173 | {
174 | $this->$key = $value;
175 | }
176 | else
177 | {
178 | throw new Oauthz_Exception_Authorize('invalid_request', $this->state);
179 | }
180 | }
181 | elseif($val !== FALSE)
182 | {
183 | $this->$key = $val;
184 | }
185 | }
186 | }
187 |
188 | $this->method = 'GET';
189 | }
190 |
191 | if(empty($params))
192 | {
193 | throw new Oauthz_Exception_Token('invalid_request');
194 | }
195 |
196 | $this->oauth_token = $params['oauth_token'];
197 | }
198 |
199 | /**
200 | * No need to authorization any more
201 | *
202 | * @access public
203 | * @param array $client
204 | * @return Oauthz_Token
205 | * @throw Oauthz_Exception_Token Error codes: invalid_scope, redirect_uri_mismatch
206 | */
207 | public function execute()
208 | {
209 | // Verify the client and the code, load the access token if successes
210 | if($client = Model_Oauthz::factory('Token')
211 | ->token($this->client_id, $this->code, $this->expires_in))
212 | {
213 | // Audit
214 | }
215 | else
216 | {
217 | // Invalid client_id
218 | throw new Oauthz_Exception_Token('unauthorized_client', $this->state);
219 | }
220 |
221 | if(isset($this->token_secret) AND $client['token_secret'] !== sha1($this->token_secret))
222 | {
223 | throw new Oauthz_Exception_Token('invalid_request', $this->state);
224 | }
225 |
226 | if($client['expires_in'] < $_SERVER['REQUEST_TIME'])
227 | {
228 | throw new Oauthz_Exception_Access('invalid_grant', $this->state);
229 | }
230 |
231 | $token = new Oauthz_Token;
232 |
233 | // TODO: issue "mac" OAuth Access Token Type
234 | $token->token_type = $client['token_type'];
235 | $token->access_token = $client['access_token'];
236 | $token->refresh_token = $client['refresh_token'];
237 | $token->expires_in = $client['expires_in'];
238 |
239 | // merge other token properties, e.g. {"mac_key":"adijq39jdlaska9asud","mac_algorithm":"hmac-sha-256"}
240 | if($client['options'] AND $option = json_decode($client['options'], TRUE))
241 | {
242 | foreach($option as $key => $val)
243 | {
244 | $token->$key = $val;
245 | }
246 | }
247 |
248 | isset($this->state['state']) AND $token->state = $this->state['state'];
249 |
250 | return $this->redirect_uri.'#'.$token->as_query();
251 | }
252 |
253 | /**
254 | * MUST verify that the verification code, client identity, client secret,
255 | * and redirection URI are all valid and match its stored association.
256 | *
257 | * @access public
258 | * @param array $client
259 | * @return Oauthz_Token
260 | * @throw Oauthz_Exception_Token Error codes: invalid_request, unauthorized_client
261 | * @todo impletement timestamp, nonce, signature checking
262 | */
263 | public function access_token($client)
264 | {
265 | if($client['access_token'] !== $this->oauth_token)
266 | {
267 | throw new Oauthz_Exception_Access('unauthorized_client', $this->state);
268 | }
269 |
270 | if($client['token_type'] !== $this->token_type)
271 | {
272 | throw new Oauthz_Exception_Access('unauthorized_client', $this->state);
273 | }
274 |
275 | if(isset($this->scope) AND ! empty($client['scope']))
276 | {
277 | if( ! in_array($this->scope, explode(' ', $client['scope'])))
278 | throw new Oauthz_Exception_Access('invalid_scope', $this->state);
279 | }
280 |
281 | $token = new Oauthz_Token;
282 |
283 | if(isset($this->format))
284 | {
285 | $token->format = $this->format;
286 | }
287 |
288 | //switch($token->token_type)
289 | //{
290 |
291 | //}
292 |
293 | return $token;
294 | }
295 |
296 | } // END Oauthz_Extension_Token
297 |
--------------------------------------------------------------------------------
/classes/model/oauthz/client.php:
--------------------------------------------------------------------------------
1 |
6 | * @package Oauthz
7 | * @copyright (c) 2010 OALite
8 | * @license ISC License (ISCL)
9 | * @link http://oalite.com
10 | * @see Model_Oauthz
11 | * *
12 | */
13 | class Model_Oauthz_Client extends Model_Oauthz {
14 |
15 | public function get($server_id, $user_id)
16 | {
17 | return DB::select('server_id','client_id','client_secret','redirect_uri','scope','secret_type','ssh_key','app_name','app_desc','app_profile','app_purpose','user_id','user_level','enabled','created','modified')
18 | ->from('t_oauth_clients')
19 | ->where('server_id', '=', $server_id)
20 | ->where('user_id','=', $user_id)
21 | ->execute($this->_db)
22 | ->current();
23 | }
24 |
25 | public function lookup($client_id)
26 | {
27 | return DB::select('*')
28 | ->from('t_oauth_clients')
29 | ->where('client_id', '=', $client_id)
30 | ->execute($this->_db)
31 | ->current();
32 | }
33 |
34 | /**
35 | * Insert server
36 | *
37 | * @access public
38 | * @param array $params
39 | * client_id: AKA. API key
40 | * client_secret: AKA. API secret
41 | * redirect_uri: AKA. Callback URI
42 | * scope: May be create, read, update or delete. so on so for
43 | * secret_type: Secret signature encrypt type. e.g
44 | * ssh_key: SSH public keys
45 | * app_name: Application Name
46 | * app_desc: Application Description, When users authenticate via your app, this is what they'll see.
47 | * app_profile: Application Profile: Web Client Application, Native Application, Browser Application, Autonomous clients
48 | * user_id: Ref# from users table
49 | * user_level: diferent client levels have different max request times
50 | * enabled: 0: waiting for system administrator audit; 1: acceptable; 2: ban
51 | * created: create datetime
52 | * modified: modified datetime
53 | *
54 | * @return mix array(insert_id, affect_rows) or validate object
55 | */
56 | public function append(array $params, $prefix = 'OAL@')
57 | {
58 | $params['client_id'] = $prefix.strtoupper(uniqid());
59 |
60 | $valid = Validate::factory($params)
61 | ->filter(TRUE, 'trim')
62 | ->rule('client_secret', 'not_empty')
63 | ->rule('redirect_uri', 'not_empty')
64 | ->rule('app_name', 'not_empty');
65 |
66 | $rules = array_intersect_key(array (
67 | 'client_id' => array ('max_length' => array (128)),
68 | 'client_secret' => array ('max_length' => array (128)),
69 | 'redirect_uri' => array ('max_length' => array (512)),
70 | 'scope' => array ('max_length' => array (256)),
71 | 'secret_type' => array ('in_array' => array (array ('plaintext','md5','rsa-sha1','hmac-sha1')),),
72 | 'ssh_key' => array ('max_length' => array (512)),
73 | 'app_name' => array ('max_length' => array (128)),
74 | 'app_desc' => array ('max_length' => array (65535)),
75 | 'app_profile' => array ('in_array' => array (array ('webserver','native','useragent','autonomous')),),
76 | 'app_purpose' => array ('max_length' => array (512)),
77 | 'user_level' => array ('range' => array (0,255)),
78 | 'enabled' => array ('range' => array (0,255)),
79 | 'modified' => array ('range' => array (0,2147483647)),
80 | ), $params);
81 |
82 | foreach($rules as $field => $rule)
83 | foreach($rule as $r => $p)
84 | $valid->rule($field, $r, $p);
85 |
86 | // TODO: redirect_uri MUST NOT include a fragment component.
87 | // The client MUST NOT include any untrusted third-party scripts in the redirection endpoint
88 | // response (e.g. third-party analytics, social plug-ins, ad networks)
89 | // The client SHOULD NOT include any third-party scripts in the redirection endpoint response.
90 |
91 | if($valid->check())
92 | {
93 | $valid = $valid->as_array();
94 |
95 | if($this->unique_client($valid['redirect_uri'], $params['user_id']))
96 | {
97 | return $valid->error('redirect_uri', 'not unique');
98 | }
99 |
100 | foreach($valid as $key => $val)
101 | {
102 | if($val === '') $valid[$key] = NULL;
103 | }
104 |
105 | $valid['user_id'] = $params['user_id'];
106 | $valid['created'] = $_SERVER['REQUEST_TIME'];
107 | $valid['client_secret'] = sha1($params['client_secret']);
108 |
109 | $query = DB::insert('t_oauth_clients', array_keys($valid))
110 | ->values(array_values($valid))
111 | ->execute($this->_db);
112 |
113 | $valid['server_id'] = $query[0];
114 | $valid['affected_rows'] = $query[1];
115 |
116 | $valid += $params;
117 | }
118 |
119 | // Validation data, or collection of the errors
120 | return $valid;
121 | }
122 |
123 | /**
124 | * Update server
125 | *
126 | * @access public
127 | * @param int $server_id
128 | * @param array $params
129 | * client_id: AKA. API key
130 | * client_secret: AKA. API secret
131 | * redirect_uri: AKA. Callback URI
132 | * scope: May be create, read, update or delete. so on so for
133 | * secret_type: Secret signature encrypt type. e.g
134 | * ssh_key: SSH public keys
135 | * app_name: Application Name
136 | * app_desc: Application Description, When users authenticate via your app, this is what they'll see.
137 | * app_profile: Application Profile: Web Client Application, Native Application, Browser Application, Autonomous clients
138 | * user_id: Ref# from users table
139 | * user_level: diferent client levels have different max request times
140 | * enabled: 0: waiting for system administrator audit; 1: acceptable; 2: ban
141 | * created: create datetime
142 | * modified: modified datetime
143 | *
144 | * @return mix update rows affect or validate object
145 | */
146 | public function update($server_id, array $params)
147 | {
148 |
149 | if(empty($params['client_secret'])) unset($params['client_secret']);
150 |
151 | $valid = Validate::factory($params)
152 | ->filter(TRUE, 'trim');
153 |
154 | $rules = array_intersect_key(array (
155 | 'client_id' => array ('not_empty' => NULL, 'max_length' => array (128)),
156 | 'client_secret' => array ('max_length' => array (128)),
157 | 'redirect_uri' => array ('not_empty' => NULL, 'max_length' => array (512)),
158 | 'scope' => array ('max_length' => array (256)),
159 | 'secret_type' => array ('in_array' => array (array ('plaintext','md5','rsa-sha1','hmac-sha1')),),
160 | 'ssh_key' => array ('max_length' => array (512)),
161 | 'app_name' => array ('not_empty' => NULL, 'max_length' => array (128)),
162 | 'app_desc' => array ('max_length' => array (65535)),
163 | 'app_profile' => array ('in_array' => array (array ('webserver','native','useragent','autonomous')),),
164 | 'app_purpose' => array ('max_length' => array (512)),
165 | 'user_level' => array ('range' => array (0,255)),
166 | 'enabled' => array ('range' => array (0,255)),
167 | 'created' => array ('not_empty' => NULL, 'range' => array (0,4294967295)),
168 | ), $params);
169 |
170 | foreach($rules as $field => $rule)
171 | foreach($rule as $r => $p)
172 | $valid->rule($field, $r, $p);
173 |
174 | if($valid->check())
175 | {
176 | $valid = $valid->as_array();
177 |
178 | if($this->unique_client($valid['redirect_uri'], $params['user_id']) === 1)
179 | {
180 | unset($valid['redirect_uri']);
181 | }
182 |
183 | foreach($valid as $key => $val)
184 | {
185 | if($val === '') $valid[$key] = NULL;
186 | }
187 |
188 | $valid['modified'] = $_SERVER['REQUEST_TIME'];
189 | $valid['affected_rows'] = DB::update('t_oauth_clients')
190 | ->set($valid)
191 | ->where('server_id', '=', $server_id)
192 | ->where('user_id', '=', $params['user_id'])
193 | ->execute($this->_db);
194 |
195 | $valid += $params;
196 | }
197 |
198 | // Validation data, or collection of the errors
199 | return $valid;
200 | }
201 |
202 | public function delete($server_id, $user_id)
203 | {
204 | return ctype_digit((string) $server_id)
205 | ? DB::delete('t_oauth_clients')
206 | ->where('server_id', '=', $server_id)
207 | ->where('user_id','=', $user_id)
208 | ->execute($this->_db)
209 | : NULL;
210 | }
211 |
212 | /**
213 | * List servers
214 | *
215 | * @access public
216 | * @param array $params
217 | * @param Pagination $pagination default [ NULL ] passed by reference
218 | * @param boolean $calc_total default [ TRUE ] is needed to caculate the total records for pagination
219 | * @return array array('servers' => data, 'orderby' => $params['orderby'], 'pagination' => $pagination)
220 | */
221 | public function lists(array $params, $pagination = NULL, $calc_total = TRUE)
222 | {
223 | $pagination instanceOf Pagination OR $pagination = new Pagination;
224 |
225 | $sql = 'FROM `t_oauth_clients` ';
226 |
227 | // Customize where from params
228 | $sql .= 'WHERE user_id='.$this->_db->quote($params['user_id']);
229 |
230 | // caculte the total rows
231 | if($calc_total === TRUE)
232 | {
233 | $pagination->total_items = $this->_db->query(
234 | Database::SELECT, 'SELECT COUNT(`server_id`) num_rows '.$sql, FALSE
235 | )->get('num_rows');
236 |
237 | $data['pagination'] = $pagination;
238 |
239 | if($pagination->total_items === 0)
240 | {
241 | $data['servers'] = array();
242 | isset($params['orderby']) AND $data['orderby'] = $params['orderby'];
243 | return $data;
244 | }
245 | }
246 |
247 | // Customize order by from params
248 | if(isset($params['orderby']))
249 | {
250 | switch($params['orderby'])
251 | {
252 | case 'uri':
253 | $sql .= ' ORDER BY redirect_uri DESC';
254 | break;
255 | case 'level':
256 | $sql .= ' ORDER BY user_level DESC';
257 | break;
258 | case 'appname':
259 | $sql .= ' ORDER BY app_name DESC';
260 | break;
261 | default:
262 | $params['orderby'] = 'client_id';
263 | $sql .= ' ORDER BY client_id DESC';
264 | break;
265 | }
266 | $data['orderby'] = $params['orderby'];
267 | }
268 |
269 | $sql .= " LIMIT {$pagination->offset}, {$pagination->items_per_page}";
270 |
271 | $data['servers'] = $this->_db->query(Database::SELECT, 'SELECT * '.$sql, FALSE);
272 |
273 | return $data;
274 | }
275 |
276 | protected function unique_client($redirect_uri, $user_id)
277 | {
278 | // Check if the username already exists in the database
279 | return DB::select(array(DB::expr('COUNT(1)'), 'total'))
280 | ->from('t_oauth_clients')
281 | ->where('redirect_uri', '=', $redirect_uri)
282 | ->where('user_id', '=', $user_id)
283 | ->execute($this->_db)
284 | ->get('total');
285 | }
286 |
287 | } // END Model_Oauthz_Client
288 |
--------------------------------------------------------------------------------