diff --git a/composer.json b/composer.json index f7ed28b0..c61b59d3 100644 --- a/composer.json +++ b/composer.json @@ -37,5 +37,8 @@ "psr-0": { "Oauth2": "src/" } + }, + "suggest": { + "lncd/oauth2-facebook": "Adds support for Facebook as an IDP" } } \ No newline at end of file diff --git a/src/Oauth2/Client/Client.php b/src/Oauth2/Client/Client.php deleted file mode 100755 index 8a14c050..00000000 --- a/src/Oauth2/Client/Client.php +++ /dev/null @@ -1,19 +0,0 @@ -result = $result; - - $code = isset($result['code']) ? $result['code'] : 0; - - if (isset($result['error'])) { - - // OAuth 2.0 Draft 10 style - $message = $result['error']; - - } elseif (isset($result['message'])) { - - // cURL style - $message = $result['message']; - - } else { - - $message = 'Unknown Error.'; - - } - - parent::__construct($message, $code); - } - - /** - * Returns the associated type for the error. This will default to - * 'Exception' when a type is not available. - * - * @return - * The type for the error. - */ - public function getType() - { - if (isset($this->result['error'])) { - - $message = $this->result['error']; - - if (is_string($message)) { - // OAuth 2.0 Draft 10 style - return $message; - } - } - - return 'Exception'; - } - - /** - * To make debugging easier. - * - * @returns - * The string representation of the error. - */ - public function __toString() - { - $str = $this->getType() . ': '; - - if ($this->code != 0) { - $str .= $this->code . ': '; - } - - return $str . $this->message; - } - -} \ No newline at end of file diff --git a/src/Oauth2/Client/IDP.php b/src/Oauth2/Client/IDP.php index 6338fd9b..2dbe182b 100644 --- a/src/Oauth2/Client/IDP.php +++ b/src/Oauth2/Client/IDP.php @@ -2,128 +2,229 @@ namespace OAuth2\Client; -use Guzzle\Service\Client; +use Guzzle\Service\Client as GuzzleClient; -class IDPException extends \Exception {} +class IDPException extends \Exception +{ + protected $result; -class IDP { + public function __construct($result) + { + $this->result = $result; - public $clientId = ''; + $code = isset($result['code']) ? $result['code'] : 0; - public $clientSecret = ''; + if (isset($result['error'])) { - public $redirectUri = ''; + // OAuth 2.0 Draft 10 style + $message = $result['error']; - public $name; + } elseif (isset($result['message'])) { - public $uidKey = 'uid'; + // cURL style + $message = $result['message']; - public $scopes = array(); + } else { - public $method = 'post'; + $message = 'Unknown Error.'; - public $scopeSeperator = ','; + } - public $responseType = 'json'; + parent::__construct($message['message'], $message['code']); + } - public function __construct() - { - //$this->redirectUri = $_SERVER[] - } + public function getType() + { + if (isset($this->result['error'])) { - public function __get($key) - { - return $this->$key; - } + $message = $this->result['error']; - abstract public function urlAuthorize(); + if (is_string($message)) { + // OAuth 2.0 Draft 10 style + return $message; + } + } - abstract public function urlAccessToken(); + return 'Exception'; + } - abstract public function urlUserInfo(); + /** + * To make debugging easier. + * + * @returns + * The string representation of the error. + */ + public function __toString() + { + $str = $this->getType() . ': '; - public function authorize($options = array()) - { - $state = md5(uniqid(rand(), TRUE)); - setcookie($this->name.'_authorize_state', $state); + if ($this->code != 0) { + $str .= $this->code . ': '; + } - $params = array( - 'client_id' => $this->clientId, - 'redirect_uri' => $this->redirectUri, - 'state' => $state, - 'scope' => is_array($this->scope) ? implode($this->scopeSeperator, $this->scope) : $this->scope, - 'response_type' => isset($options['response_type']) ? $options['response_type'] : 'code', - 'approval_prompt' => 'force' // - google force-recheck - ); + return $str . $this->message; + } - header('Location: ' . $this->urlAuthorize().'?'.http_build_query($params)); - exit; - } +} - public function getAccessToken() - { - $params = array( - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - 'grant_type' => isset($options['grant_type']) ? $options['grant_type'] : 'authorization_code', - ); +abstract class IDP { - switch ($params['grant_type']) { + public $clientId = ''; - case 'authorization_code': - $params['code'] = $code; - $params['redirect_uri'] = isset($options['redirect_uri']) ? $options['redirect_uri'] : $this->redirect_uri; - break; + public $clientSecret = ''; - case 'refresh_token': - $params['refresh_token'] = $code; - break; + public $redirectUri = ''; - } + public $name; - switch ($this->method) { + public $uidKey = 'uid'; - case 'get': - $client = new Client($this->urlAccessToken() .= '?'.http_build_query($params)); - $response = $client->get(); - break; + public $scopes = array(); - default: - $client = new Client($this->urlAccessToken()); - $response = $client->{$this->method}(null, null, $params); - break; + public $method = 'post'; - } + public $scopeSeperator = ','; - switch ($this->responseType) { + public $responseType = 'json'; - case 'json': - $result = json_decode($response, true); - break; + public function __construct($options) + { + foreach ($options as $option => $value) { + if (isset($this->{$option})) { + $this->{$option} = $value; + } + } + } - case 'string': - parse_str($response, $result); - break; + abstract public function urlAuthorize(); - } + abstract public function urlAccessToken(); - if (isset($result['error']) && ! empty($result['error'])) { + abstract public function urlUserDetails(\Oauth2\Client\Token\Access $token); - throw new Oauth2\Client\IDPException($result); + abstract public function userDetails($response, \Oauth2\Client\Token\Access $token); - } + public function authorize($options = array()) + { + $state = md5(uniqid(rand(), TRUE)); + setcookie($this->name.'_authorize_state', $state); - switch ($params['grant_type']) { + $params = array( + 'client_id' => $this->clientId, + 'redirect_uri' => $this->redirectUri, + 'state' => $state, + 'scope' => is_array($this->scope) ? implode($this->scopeSeperator, $this->scope) : $this->scope, + 'response_type' => isset($options['response_type']) ? $options['response_type'] : 'code', + 'approval_prompt' => 'force' // - google force-recheck + ); - case 'authorization_code': - return Oauth2\Client\Token::factory('access', $result); - break; + header('Location: ' . $this->urlAuthorize().'?'.http_build_query($params)); + exit; + } - case 'refresh_token': - return Oauth2\Client\Token::factory('refresh', $result); - break; + public function getAccessToken($code = NULL, $options = array()) + { + if ($code === NULL) { + throw new \BadMethodCallException('Missing authorization code'); + } - } - } + $params = array( + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'grant_type' => isset($options['grantType']) ? $options['grantType'] : 'authorization_code', + ); + + switch ($params['grant_type']) { + + case 'authorization_code': + $params['code'] = $code; + $params['redirect_uri'] = isset($options['redirectUri']) ? $options['redirectUri'] : $this->redirectUri; + break; + + case 'refresh_token': + $params['refresh_token'] = $code; + break; + + } + + try { + + switch ($this->method) { + + case 'get': + + $client = new GuzzleClient($this->urlAccessToken() . '?' . http_build_query($params)); + $request = $client->send(); + $response = $request->getBody(); + + break; + + case 'post': + + $client = new GuzzleClient($this->urlAccessToken()); + $request = $client->post(null, null, $params)->send(); + $response = $request->getBody(); + + break; + + } + + } + + catch (\Guzzle\Http\Exception\BadResponseException $e) + { + $raw_response = explode("\n", $e->getResponse()); + $response = end($raw_response); + } + + switch ($this->responseType) { + + case 'json': + $result = json_decode($response, true); + break; + + case 'string': + parse_str($response, $result); + break; + + } + + if (isset($result['error']) && ! empty($result['error'])) { + + throw new \Oauth2\Client\IDPException($result); + + } + + switch ($params['grant_type']) { + + case 'authorization_code': + return \Oauth2\Client\Token::factory('access', $result); + break; + + case 'refresh_token': + return \Oauth2\Client\Token::factory('refresh', $result); + break; + + } + } + + public function getUserDetails(\Oauth2\Client\Token\Access $token) + { + $url = $this->urlUserDetails($token); + + try { + $client = new GuzzleClient($url); + $request = $client->get()->send(); + $response = $request->getBody(); + + return $this->userDetails(json_decode($response), $token); + } + + catch (\Guzzle\Http\Exception\BadResponseException $e) + { + $raw_response = explode("\n", $e->getResponse()); + throw new \Oauth2\Client\IDPException(end($raw_response)); + } + } } \ No newline at end of file diff --git a/src/Oauth2/Client/Token.php b/src/Oauth2/Client/Token.php index 6d8886c4..2cb15b12 100755 --- a/src/Oauth2/Client/Token.php +++ b/src/Oauth2/Client/Token.php @@ -16,7 +16,7 @@ abstract class Token { include_once 'Token/'.ucfirst(strtolower($name)).'.php'; - $class = $name.'Token'; + $class = 'Oauth2\Client\Token\\'.ucfirst($name); return new $class($options); } diff --git a/src/Oauth2/Client/Token/Access.php b/src/Oauth2/Client/Token/Access.php index 47a6c274..18d3cd49 100755 --- a/src/Oauth2/Client/Token/Access.php +++ b/src/Oauth2/Client/Token/Access.php @@ -11,7 +11,7 @@ namespace Oauth2\Client\Token; * @copyright (c) 2011 HappyNinjas Ltd */ -class Access extends Oauth2\Client\Token +class Access extends \Oauth2\Client\Token { /** * @var string accessToken @@ -42,26 +42,26 @@ class Access extends Oauth2\Client\Token public function __construct(array $options = null) { if ( ! isset($options['access_token'])) { - throw new Exception('Required option not passed: access_token'.PHP_EOL.print_r($options, true)); + throw new \BadMethodCallException('Required option not passed: access_token'.PHP_EOL.print_r($options, true)); } $this->accessToken = $options['access_token']; - + // Some providers (not many) give the uid here, so lets take it isset($options['uid']) and $this->uid = $options['uid']; - + //Vkontakte uses user_id instead of uid isset($options['user_id']) and $this->uid = $options['user_id']; - + //Mailru uses x_mailru_vid instead of uid isset($options['x_mailru_vid']) and $this->uid = $options['x_mailru_vid']; - + // We need to know when the token expires, add num. seconds to current time isset($options['expires_in']) and $this->expires = time() + ((int) $options['expires_in']); - + // Facebook is just being a spec ignoring jerk isset($options['expires']) and $this->expires = time() + ((int) $options['expires']); - + // Grab a refresh token so we can update access tokens when they expires isset($options['refresh_token']) and $this->refreshToken = $options['refresh_token']; } diff --git a/src/Oauth2/Client/Token/Authorize.php b/src/Oauth2/Client/Token/Authorize.php index 1d9a9b7c..f9358385 100755 --- a/src/Oauth2/Client/Token/Authorize.php +++ b/src/Oauth2/Client/Token/Authorize.php @@ -8,7 +8,7 @@ * @copyright (c) 2011 HappyNinjas Ltd */ -class Authorize extends Oauth2\Client\Token +class Authorize extends \Oauth2\Client\Token { /** * @var string code @@ -35,9 +35,9 @@ class Authorize extends Oauth2\Client\Token } elseif ( ! isset($options['redirect_uri'])) { throw new Exception('Required option not passed: redirect_uri'); - + } - + $this->code = $options['code']; $this->redirectUri = $options['redirect_uri']; }