Compare commits
No commits in common. "2.0" and "master" have entirely different histories.
15 changed files with 708 additions and 120 deletions
|
@ -23,7 +23,7 @@
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.4",
|
"php": ">=5.4",
|
||||||
"bshaffer/oauth2-server-php": "v1.5"
|
"league/oauth2-server": "4.0.x-dev"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"mongodb/mongo-php-driver": "Required to use the Mongo storage engine",
|
"mongodb/mongo-php-driver": "Required to use the Mongo storage engine",
|
||||||
|
|
170
composer.lock
generated
170
composer.lock
generated
|
@ -4,34 +4,33 @@
|
||||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "f90250145c5046194b1c3187fc90513a",
|
"hash": "65e330b4eb2873d61093fc36aa624d0f",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "bshaffer/oauth2-server-php",
|
"name": "league/event",
|
||||||
"version": "v1.5",
|
"version": "1.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bshaffer/oauth2-server-php.git",
|
"url": "https://github.com/thephpleague/event.git",
|
||||||
"reference": "74fcc75e47614c1417c750e907a44567d9ceee1f"
|
"reference": "06adb7ce55b93346be43a3ba677ac613bbf288a2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/bshaffer/oauth2-server-php/zipball/74fcc75e47614c1417c750e907a44567d9ceee1f",
|
"url": "https://api.github.com/repos/thephpleague/event/zipball/06adb7ce55b93346be43a3ba677ac613bbf288a2",
|
||||||
"reference": "74fcc75e47614c1417c750e907a44567d9ceee1f",
|
"reference": "06adb7ce55b93346be43a3ba677ac613bbf288a2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.9"
|
"php": ">=5.4.0"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"require-dev": {
|
||||||
"aws/aws-sdk-php": "Required to use the DynamoDB storage engine",
|
"henrikbjorn/phpspec-code-coverage": "1.0.*@dev",
|
||||||
"predis/predis": "Required to use the Redis storage engine",
|
"phpspec/phpspec": "2.0.*@dev"
|
||||||
"thobbs/phpcassa": "Required to use the Cassandra storage engine"
|
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-4": {
|
||||||
"OAuth2": "src/"
|
"League\\Event\\": "src/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
@ -40,19 +39,143 @@
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Brent Shaffer",
|
"name": "Frank de Jonge",
|
||||||
"email": "bshafs@gmail.com",
|
"email": "info@frenky.net"
|
||||||
"homepage": "http://brentertainment.com"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "OAuth2 Server for PHP",
|
"description": "Event package",
|
||||||
"homepage": "http://github.com/bshaffer/oauth2-server-php",
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"auth",
|
"emitter",
|
||||||
"oauth",
|
"event",
|
||||||
"oauth2"
|
"listener"
|
||||||
],
|
],
|
||||||
"time": "2014-08-28 02:13:42"
|
"time": "2014-09-09 14:40:43"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "league/oauth2-server",
|
||||||
|
"version": "dev-develop",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/thephpleague/oauth2-server.git",
|
||||||
|
"reference": "6333a975f8fb51111b447a7e85806e4519fb52b9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/thephpleague/oauth2-server/zipball/6333a975f8fb51111b447a7e85806e4519fb52b9",
|
||||||
|
"reference": "6333a975f8fb51111b447a7e85806e4519fb52b9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"league/event": "1.0.*",
|
||||||
|
"php": ">=5.4.0",
|
||||||
|
"symfony/http-foundation": "~2.1"
|
||||||
|
},
|
||||||
|
"replace": {
|
||||||
|
"league/oauth2server": "*",
|
||||||
|
"lncd/oauth2": "*"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"alexbilbie/fizzfuzz": "dev-develop",
|
||||||
|
"codeception/codeception": "2.0.*",
|
||||||
|
"league/phpunit-coverage-listener": "~1.0",
|
||||||
|
"mockery/mockery": "~0.9",
|
||||||
|
"phpunit/phpunit": "~4.0",
|
||||||
|
"squizlabs/php_codesniffer": "~1.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-develop": "4.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"League\\OAuth2\\Server\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alex Bilbie",
|
||||||
|
"email": "hello@alexbilbie.com",
|
||||||
|
"homepage": "http://www.alexbilbie.com",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
|
||||||
|
"homepage": "http://oauth2.thephpleague.com/",
|
||||||
|
"keywords": [
|
||||||
|
"Authentication",
|
||||||
|
"api",
|
||||||
|
"auth",
|
||||||
|
"authorisation",
|
||||||
|
"authorization",
|
||||||
|
"oauth",
|
||||||
|
"oauth 2",
|
||||||
|
"oauth 2.0",
|
||||||
|
"oauth2",
|
||||||
|
"protect",
|
||||||
|
"resource",
|
||||||
|
"secure",
|
||||||
|
"server"
|
||||||
|
],
|
||||||
|
"time": "2014-10-03 13:42:01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/http-foundation",
|
||||||
|
"version": "dev-master",
|
||||||
|
"target-dir": "Symfony/Component/HttpFoundation",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/HttpFoundation.git",
|
||||||
|
"reference": "c24942a7ec2d8409d1f60d02c4460ca8317e885a"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/c24942a7ec2d8409d1f60d02c4460ca8317e885a",
|
||||||
|
"reference": "c24942a7ec2d8409d1f60d02c4460ca8317e885a",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/expression-language": "~2.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.6-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-0": {
|
||||||
|
"Symfony\\Component\\HttpFoundation\\": ""
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"Symfony/Component/HttpFoundation/Resources/stubs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "http://symfony.com/contributors"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony HttpFoundation Component",
|
||||||
|
"homepage": "http://symfony.com",
|
||||||
|
"time": "2014-10-07 14:06:18"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
|
@ -1311,6 +1434,7 @@
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
"stability-flags": {
|
"stability-flags": {
|
||||||
|
"league/oauth2-server": 20,
|
||||||
"phpunit/phpunit": 20,
|
"phpunit/phpunit": 20,
|
||||||
"satooshi/php-coveralls": 20
|
"satooshi/php-coveralls": 20
|
||||||
},
|
},
|
||||||
|
|
129
sql/oauth2.sql
Normal file
129
sql/oauth2.sql
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
CREATE TABLE `oauth_clients` (
|
||||||
|
`id` CHAR(40) NOT NULL,
|
||||||
|
`secret` CHAR(40) NOT NULL,
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`auto_approve` TINYINT(1) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `u_oacl_clse_clid` (`secret`,`id`)
|
||||||
|
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_endpoints` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`client_id` char(40) NOT NULL,
|
||||||
|
`redirect_uri` varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `i_oaclen_clid` (`client_id`),
|
||||||
|
CONSTRAINT `f_oaclen_clid`
|
||||||
|
FOREIGN KEY (`client_id`)
|
||||||
|
REFERENCES `oauth_clients` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_sessions` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`client_id` char(40) NOT NULL,
|
||||||
|
`owner_type` enum('user','client') NOT NULL DEFAULT 'user',
|
||||||
|
`owner_id` varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `i_uase_clid_owty_owid` (`client_id`,`owner_type`,`owner_id`),
|
||||||
|
CONSTRAINT `f_oase_clid`
|
||||||
|
FOREIGN KEY (`client_id`)
|
||||||
|
REFERENCES `oauth_clients` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_access_tokens` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`session_id` int(10) unsigned NOT NULL,
|
||||||
|
`access_token` char(40) NOT NULL,
|
||||||
|
`expires_at` int(10) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `u_oaseacto_acto_seid` (`access_token`,`session_id`),
|
||||||
|
KEY `f_oaseto_seid` (`session_id`),
|
||||||
|
CONSTRAINT `f_oaseto_seid`
|
||||||
|
FOREIGN KEY (`session_id`)
|
||||||
|
REFERENCES `oauth_sessions` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_authorization_codes` (
|
||||||
|
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`session_id` int(10) unsigned NOT NULL,
|
||||||
|
`authorization_code` char(40) NOT NULL,
|
||||||
|
`expires_at` int(10) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `session_id` (`session_id`),
|
||||||
|
CONSTRAINT `oauth_authorization_codes_ibfk_1`
|
||||||
|
FOREIGN KEY (`session_id`)
|
||||||
|
REFERENCES `oauth_sessions` (`id`)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_redirect_uris` (
|
||||||
|
`session_id` int(10) unsigned NOT NULL,
|
||||||
|
`redirect_uri` varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (`session_id`),
|
||||||
|
CONSTRAINT `f_oasere_seid`
|
||||||
|
FOREIGN KEY (`session_id`)
|
||||||
|
REFERENCES `oauth_sessions` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_refresh_tokens` (
|
||||||
|
`access_token_id` int(10) unsigned NOT NULL,
|
||||||
|
`refresh_token` char(40) NOT NULL,
|
||||||
|
`expires_at` int(10) unsigned NOT NULL,
|
||||||
|
`client_id` char(40) NOT NULL,
|
||||||
|
PRIMARY KEY (`access_token_id`),
|
||||||
|
KEY `client_id` (`client_id`),
|
||||||
|
CONSTRAINT `oauth_refresh_tokens_ibfk_1`
|
||||||
|
FOREIGN KEY (`client_id`)
|
||||||
|
REFERENCES `oauth_clients` (`id`)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `f_oasetore_setoid`
|
||||||
|
FOREIGN KEY (`access_token_id`)
|
||||||
|
REFERENCES `oauth_access_tokens` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_scopes` (
|
||||||
|
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`scope` varchar(255) NOT NULL,
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`description` varchar(255) DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `u_oasc_sc` (`scope`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_access_token_scopes` (
|
||||||
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`access_token_id` int(10) unsigned DEFAULT NULL,
|
||||||
|
`scope_id` smallint(5) unsigned NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `u_setosc_setoid_scid` (`access_token_id`,`scope_id`),
|
||||||
|
KEY `f_oasetosc_scid` (`scope_id`),
|
||||||
|
CONSTRAINT `f_oasetosc_scid`
|
||||||
|
FOREIGN KEY (`scope_id`)
|
||||||
|
REFERENCES `oauth_scopes` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE NO ACTION,
|
||||||
|
CONSTRAINT `f_oasetosc_setoid`
|
||||||
|
FOREIGN KEY (`access_token_id`)
|
||||||
|
REFERENCES `oauth_access_tokens` (`id`)
|
||||||
|
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE `oauth_authorization_code_scopes` (
|
||||||
|
`authorization_code_id` int(10) unsigned NOT NULL,
|
||||||
|
`scope_id` smallint(5) unsigned NOT NULL,
|
||||||
|
KEY `authorization_code_id` (`authorization_code_id`),
|
||||||
|
KEY `scope_id` (`scope_id`),
|
||||||
|
CONSTRAINT `oauth_authorization_code_scopes_ibfk_2`
|
||||||
|
FOREIGN KEY (`scope_id`)
|
||||||
|
REFERENCES `oauth_scopes` (`id`)
|
||||||
|
ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `oauth_authorization_code_scopes_ibfk_1`
|
||||||
|
FOREIGN KEY (`authorization_code_id`)
|
||||||
|
REFERENCES `oauth_authorization_codes` (`id`)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Mongo extends Object
|
||||||
|
|
||||||
// Instantiates our Mongo client
|
// Instantiates our Mongo client
|
||||||
$instance = new \MongoClient($mongo['server']);
|
$instance = new \MongoClient($mongo['server']);
|
||||||
$instance = $instance->$mongo['database'];
|
$instance->selectDB($mongo['database']);
|
||||||
|
|
||||||
// Caches the instance for possible reuse later
|
// Caches the instance for possible reuse later
|
||||||
self::$instances['Mongo'] = $instance;
|
self::$instances['Mongo'] = $instance;
|
||||||
|
|
84
src/OAuth2/AccessTokenStorage.php
Normal file
84
src/OAuth2/AccessTokenStorage.php
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\Entity\AbstractTokenEntity;
|
||||||
|
use \League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||||
|
use \League\OAuth2\Server\Entity\ScopeEntity;
|
||||||
|
use \League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||||
|
|
||||||
|
class AccessTokenStorage extends StorageAdapter implements AccessTokenInterface
|
||||||
|
{
|
||||||
|
public function get($token)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_access_tokens.*'
|
||||||
|
. ' FROM oauth_access_tokens'
|
||||||
|
. ' WHERE access_token = ?'
|
||||||
|
. ' AND expires_at >= ?;';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$token, time()]);
|
||||||
|
|
||||||
|
if (count($results) === 1)
|
||||||
|
{
|
||||||
|
return (new AccessTokenEntity($this->server))
|
||||||
|
->setId($results[0]['access_token'])
|
||||||
|
->setExpireTime($results[0]['expires_at']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScopes(AbstractTokenEntity $token)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_scopes.id, oauth_scopes.description'
|
||||||
|
. ' FROM oauth_access_token_scopes'
|
||||||
|
. ' INNER JOIN oauth_scopes'
|
||||||
|
. ' ON oauth_access_token_scopes.scope_id = oauth_scopes.id'
|
||||||
|
. ' WHERE oauth_access_token_scopes.access_token_id = ?;';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$token->getId()]);
|
||||||
|
$response = [];
|
||||||
|
|
||||||
|
if (count($results) > 0)
|
||||||
|
{
|
||||||
|
foreach ($results as $row)
|
||||||
|
{
|
||||||
|
$response[] = (new ScopeEntity($this->server))->hydrate([
|
||||||
|
'id' => $row['id'],
|
||||||
|
'description' => $row['description']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($token, $expiration, $session_id)
|
||||||
|
{
|
||||||
|
$sql = 'INSERT INTO oauth_access_tokens'
|
||||||
|
. ' (access_token, session_id, expires_at)'
|
||||||
|
. ' VALUES'
|
||||||
|
. ' (?, ?, ?);';
|
||||||
|
|
||||||
|
$this->db->execute($sql, [$token, $session_id, $expiration]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function associateScope(AbstractTokenEntity $token, ScopeEntity $scope)
|
||||||
|
{
|
||||||
|
$sql = 'INSERT INTO oauth_access_token_scopes'
|
||||||
|
. ' (access_token, scope)'
|
||||||
|
. ' VALUES'
|
||||||
|
. ' (?, ?);';
|
||||||
|
|
||||||
|
$this->db->execute($sql, [$token->getId(), $scope->getId()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(AbstractTokenEntity $token)
|
||||||
|
{
|
||||||
|
$sql = 'DELETE FROM oauth_access_token_scopes'
|
||||||
|
. ' WHERE access_token = ?;';
|
||||||
|
|
||||||
|
$this->db->execute($sql, [$token->getId()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
81
src/OAuth2/ClientStorage.php
Normal file
81
src/OAuth2/ClientStorage.php
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\Entity\ClientEntity;
|
||||||
|
use \League\OAuth2\Server\Entity\SessionEntity;
|
||||||
|
use \League\OAuth2\Server\Storage\Adapter;
|
||||||
|
use \League\OAuth2\Server\Storage\ClientInterface;
|
||||||
|
|
||||||
|
class ClientStorage extends StorageAdapter implements ClientInterface
|
||||||
|
{
|
||||||
|
public function get($client_id, $client_secret = null, $redirect_uri = null, $grant_type = null)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_clients.*';
|
||||||
|
|
||||||
|
if ($redirect_uri)
|
||||||
|
{
|
||||||
|
$sql .= ', oauth_client_redirect_uris.*'
|
||||||
|
. ' INNER JOIN oauth_redirect_uris'
|
||||||
|
. ' ON oauth_clients.id = oauth_redirect_uris.client_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= ' FROM oauth_clients WHERE oauth_clients.id = ?';
|
||||||
|
|
||||||
|
$parameters = [$client_id];
|
||||||
|
|
||||||
|
if ($client_secret)
|
||||||
|
{
|
||||||
|
$sql .= ' AND oauth_clients.secret = ?';
|
||||||
|
$parameters[] = $client_secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($redirect_uri)
|
||||||
|
{
|
||||||
|
$sql .= 'AND oauth_redirect_uris.redirect_uri = ?';
|
||||||
|
$parameters[] = $redirect_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, $parameters);
|
||||||
|
|
||||||
|
if (count($results) === 1)
|
||||||
|
{
|
||||||
|
$client = new ClientEntity($this->server);
|
||||||
|
|
||||||
|
$client->hydrate([
|
||||||
|
'id' => $results[0]['id'],
|
||||||
|
'name' => $results[0]['name']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBySession(SessionEntity $session)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_clients.id, oauth_clients.name'
|
||||||
|
. ' FROM oauth_clients'
|
||||||
|
. ' INNER JOIN oauth_sessions'
|
||||||
|
. ' ON oauth_clients.id = oauth_sessions.client_id'
|
||||||
|
. ' WHERE oauth_sessions.id = ?';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$session->getId()]);
|
||||||
|
|
||||||
|
if (count($results) === 1)
|
||||||
|
{
|
||||||
|
$client = new ClientEntity($this->server);
|
||||||
|
|
||||||
|
$client->hydrate([
|
||||||
|
'id' => $results[0]['id'],
|
||||||
|
'name' => $results[0]['name']
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $client;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
56
src/OAuth2/RefreshTokenStorage.php
Normal file
56
src/OAuth2/RefreshTokenStorage.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||||
|
use \League\OAuth2\Server\Storage\RefreshTokenInterface;
|
||||||
|
|
||||||
|
class RefreshTokenStorage extends StorageAdapter implements RefreshTokenInterface
|
||||||
|
{
|
||||||
|
public function get($token)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_refresh_tokens.*'
|
||||||
|
. ' FROM oauth_refresh_tokens'
|
||||||
|
. ' WHERE refresh_token = ?'
|
||||||
|
. ' AND expires_at >= ?;';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$token, time()]);
|
||||||
|
|
||||||
|
if (count($results) === 1)
|
||||||
|
{
|
||||||
|
return (new RefreshTokenEntity($this->server))
|
||||||
|
->setId($results[0]['refresh_token'])
|
||||||
|
->setExpireTime($results[0]['expires_at'])
|
||||||
|
->setAccessTokenId($results[0]['access_token_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($token, $expiration, $access_token)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT id FROM oauth_access_tokens WHERE access_token = ?;';
|
||||||
|
$results = $this->db->fetch($sql, [$access_token]);
|
||||||
|
$token_id = $results[0]['id'];
|
||||||
|
|
||||||
|
$sql = 'INSERT INTO oauth_refresh_tokens'
|
||||||
|
. ' (refresh_token, access_token_id, expires_at, client_id)'
|
||||||
|
. ' VALUES'
|
||||||
|
. ' (?, ?, ?, ?);';
|
||||||
|
|
||||||
|
$this->db->execute($sql, [
|
||||||
|
$token,
|
||||||
|
$token_id,
|
||||||
|
$expiration,
|
||||||
|
$this->server->getRequest()->request->get('client_id', null),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(RefreshTokenEntity $token)
|
||||||
|
{
|
||||||
|
$sql = 'DELETE FROM oauth_refresh_tokens WHERE refresh_token = ?;';
|
||||||
|
|
||||||
|
$this->db->execute($sql, [$token->getId()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
namespace Pickles\OAuth2;
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
use \OAuth2\GrantType\UserCredentials;
|
use \League\OAuth2\Exception\OAuthException;
|
||||||
use \OAuth2\Request;
|
use \League\OAuth2\Server\AuthorizationServer;
|
||||||
use \OAuth2\Response;
|
use \League\OAuth2\Server\Grant\PasswordGrant;
|
||||||
use \OAuth2\Server;
|
use \League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||||
|
use \Pickles\App\Models\User;
|
||||||
use \Pickles\Config;
|
use \Pickles\Config;
|
||||||
|
|
||||||
class Resource extends \Pickles\Resource
|
class Resource extends \Pickles\Resource
|
||||||
|
@ -25,9 +26,17 @@ class Resource extends \Pickles\Resource
|
||||||
|
|
||||||
switch (substr($_REQUEST['request'], strlen($_SERVER['__version']) + 2))
|
switch (substr($_REQUEST['request'], strlen($_SERVER['__version']) + 2))
|
||||||
{
|
{
|
||||||
case 'oauth2/token':
|
case 'oauth/access_token':
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
$server = new AuthorizationServer;
|
||||||
|
|
||||||
|
$server->setSessionStorage(new SessionStorage);
|
||||||
|
$server->setAccessTokenStorage(new AccessTokenStorage);
|
||||||
|
$server->setClientStorage(new ClientStorage);
|
||||||
|
$server->setScopeStorage(new ScopeStorage);
|
||||||
|
$server->setRefreshTokenStorage(new RefreshTokenStorage);
|
||||||
|
|
||||||
$grant_type = $_REQUEST['grant_type'];
|
$grant_type = $_REQUEST['grant_type'];
|
||||||
$grants = ['password'];
|
$grants = ['password'];
|
||||||
|
|
||||||
|
@ -41,7 +50,7 @@ class Resource extends \Pickles\Resource
|
||||||
throw new \Exception('Unsupported grant type.', 403);
|
throw new \Exception('Unsupported grant type.', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo Defaults TTLs to 1 day and 1 week respectively
|
// Defaults TTLs to 1 day and 1 week respectively
|
||||||
$token_ttl = 3600;
|
$token_ttl = 3600;
|
||||||
$refresh_ttl = 604800;
|
$refresh_ttl = 604800;
|
||||||
|
|
||||||
|
@ -65,34 +74,51 @@ class Resource extends \Pickles\Resource
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'password':
|
case 'password':
|
||||||
$storage = new Storage($this->mongo, ['user_table' => 'user']);
|
$grant = new PasswordGrant;
|
||||||
$server = new Server($storage);
|
$grant->setAccessTokenTTL($token_ttl);
|
||||||
|
|
||||||
$server->addGrantType(new UserCredentials($storage));
|
$grant->setVerifyCredentialsCallback(function ($username, $password)
|
||||||
|
|
||||||
$request = Request::createFromGlobals();
|
|
||||||
$response = new Response;
|
|
||||||
$response = $server->handleTokenRequest($request, $response);
|
|
||||||
$body = json_decode($response->getResponseBody(), true);
|
|
||||||
|
|
||||||
if (isset($body['error']))
|
|
||||||
{
|
{
|
||||||
$parameters = $response->getParameters();
|
$user = new User([
|
||||||
|
'conditions' => [
|
||||||
|
'email' => $username,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
throw new \Exception(
|
return $user->count()
|
||||||
$parameters['error_description'],
|
&& password_verify($password, $user->record['password']);
|
||||||
$response->getStatusCode()
|
});
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $body;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'refresh_token':
|
case 'refresh_token':
|
||||||
throw new \Exception('Not Implemented', 501);
|
throw new \Exception('Not Implemented', 501);
|
||||||
|
|
||||||
|
// @todo Need to work through this, appears lib is busted
|
||||||
|
$grant = new RefreshTokenGrant;
|
||||||
|
//$grant->setAccessTokenTTL($refresh_ttl);
|
||||||
|
$server->addGrantType($grant);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$server->addGrantType($grant);
|
||||||
|
|
||||||
|
// Adds the refresh token grant if enabled
|
||||||
|
if ($grant_type != 'refresh_token'
|
||||||
|
&& in_array('refresh_token', $grants))
|
||||||
|
{
|
||||||
|
if (isset($config['ttl']['refresh_token']))
|
||||||
|
{
|
||||||
|
$refresh_ttl = $config['ttl']['refresh_token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$grant = new RefreshTokenGrant;
|
||||||
|
$grant->setAccessTokenTTL($refresh_ttl);
|
||||||
|
$server->addGrantType($grant);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $server->issueAccessToken();
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
catch (OAuthException $e)
|
catch (OAuthException $e)
|
||||||
|
|
26
src/OAuth2/ScopeStorage.php
Normal file
26
src/OAuth2/ScopeStorage.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\Storage\Adapter;
|
||||||
|
use \League\OAuth2\Server\Storage\ScopeInterface;
|
||||||
|
|
||||||
|
class ScopeStorage extends StorageAdapter implements ScopeInterface
|
||||||
|
{
|
||||||
|
public function get($scope, $grant_type = null, $client_id = null)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT * FROM oauth_scopes WHERE id = ?;';
|
||||||
|
$results = $this->db->fetch($sql, [$scope]);
|
||||||
|
|
||||||
|
if (count($results) === 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (new ScopeEntity($this->server))->hydrate([
|
||||||
|
'id' => $result[0]['id'],
|
||||||
|
'description' => $result[0]['description'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
106
src/OAuth2/SessionStorage.php
Normal file
106
src/OAuth2/SessionStorage.php
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||||
|
use \League\OAuth2\Server\Entity\AuthCodeEntity;
|
||||||
|
use \League\OAuth2\Server\Entity\ScopeEntity;
|
||||||
|
use \League\OAuth2\Server\Entity\SessionEntity;
|
||||||
|
use \League\OAuth2\Server\Storage\Adapter;
|
||||||
|
use \League\OAuth2\Server\Storage\SessionInterface;
|
||||||
|
|
||||||
|
class SessionStorage extends StorageAdapter implements SessionInterface
|
||||||
|
{
|
||||||
|
public function getByAccessToken(AccessTokenEntity $access_token)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_sessions.id, oauth_sessions.owner_type,'
|
||||||
|
. ' oauth_sessions.owner_id, oauth_sessions.client_id,'
|
||||||
|
. ' oauth_sessions.client_redirect_uri'
|
||||||
|
. ' FROM oauth_sessions'
|
||||||
|
. ' INNER JOIN oauth_access_tokens'
|
||||||
|
. ' ON oauth_access_tokens.session_id = oauth_sessions.id'
|
||||||
|
. ' WHERE oauth_access_tokens.access_token = ?;';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$access_token->getId()]);
|
||||||
|
|
||||||
|
if (count($results) === 1)
|
||||||
|
{
|
||||||
|
$session = new SessionEntity($this->server);
|
||||||
|
$session->setId($result[0]['id']);
|
||||||
|
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
|
||||||
|
|
||||||
|
return $session;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getByAuthCode(AuthCodeEntity $auth_code)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_sessions.id, oauth_sessions.owner_type,'
|
||||||
|
. ' oauth_sessions.owner_id, oauth_sessions.client_id,'
|
||||||
|
. ' oauth_sessions.client_redirect_uri'
|
||||||
|
. ' FROM oauth_sessions'
|
||||||
|
. ' INNER JOIN oauth_authorization_codes'
|
||||||
|
. ' ON oauth_authorization_codes.session_id = oauth_sessions.id'
|
||||||
|
. ' WHERE oauth_authorization_codes.authorization_code = ?;';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$auth_code->getId()]);
|
||||||
|
|
||||||
|
if (count($results) === 1)
|
||||||
|
{
|
||||||
|
$session = new SessionEntity($this->server);
|
||||||
|
$session->setId($result[0]['id']);
|
||||||
|
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
|
||||||
|
|
||||||
|
return $session;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getScopes(SessionEntity $session)
|
||||||
|
{
|
||||||
|
$sql = 'SELECT oauth_sessions.*'
|
||||||
|
. ' FROM oauth_sessions'
|
||||||
|
. ' INNER JOIN oauth_access_token_scopes'
|
||||||
|
. ' ON oauth_sessions.id = oauth_access_token_scopes.access_token_id'
|
||||||
|
. ' INNER JOIN oauth_scopes'
|
||||||
|
. ' ON oauth_scopes.id = oauth_access_token_scopes.scope_id'
|
||||||
|
. ' WHERE oauth_sessions.id = ?;';
|
||||||
|
|
||||||
|
$results = $this->db->fetch($sql, [$session->getId()]);
|
||||||
|
$scopes = [];
|
||||||
|
|
||||||
|
foreach ($results as $scope)
|
||||||
|
{
|
||||||
|
$scopes[] = (new ScopeEntity($this->server))->hydrate([
|
||||||
|
'id' => $scope['id'],
|
||||||
|
'description' => $scope['description'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($owner_type, $owner_id, $client_id, $client_redirect_uri = null)
|
||||||
|
{
|
||||||
|
$sql = 'INSERT INTO oauth_sessions'
|
||||||
|
. ' (owner_type, owner_id, client_id)'
|
||||||
|
. ' VALUES'
|
||||||
|
. ' (?, ?, ?);';
|
||||||
|
|
||||||
|
return $this->db->execute($sql, [$owner_type, $owner_id, $client_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function associateScope(SessionEntity $session, ScopeEntity $scope)
|
||||||
|
{
|
||||||
|
$sql = 'INSERT INTO oauth_access_token_scopes'
|
||||||
|
. ' (access_token_id, scope_id)'
|
||||||
|
. ' VALUES'
|
||||||
|
. ' (?, ?);';
|
||||||
|
|
||||||
|
$this->db->execute($sql, [$session->getId(), $scope->getId()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Pickles\OAuth2;
|
|
||||||
|
|
||||||
use \OAuth2\Storage\Mongo;
|
|
||||||
|
|
||||||
class Storage extends Mongo
|
|
||||||
{
|
|
||||||
private $mongo;
|
|
||||||
|
|
||||||
public function __construct($connection, $config = [])
|
|
||||||
{
|
|
||||||
parent::__construct($connection, $config);
|
|
||||||
|
|
||||||
$this->mongo = \Pickles\Mongo::getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUser($email)
|
|
||||||
{
|
|
||||||
return $this->mongo->user->findOne(['email' => $email]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUserDetails($email)
|
|
||||||
{
|
|
||||||
if ($user = $this->getUser($email))
|
|
||||||
{
|
|
||||||
$user['user_id'] = $user['_id']->{'$id'};
|
|
||||||
}
|
|
||||||
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function checkPassword($user, $password)
|
|
||||||
{
|
|
||||||
return $user && password_verify($password, $user['password']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
20
src/OAuth2/StorageAdapter.php
Normal file
20
src/OAuth2/StorageAdapter.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Pickles\OAuth2;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\Storage\Adapter;
|
||||||
|
use \Pickles\Config;
|
||||||
|
use \Pickles\Database;
|
||||||
|
|
||||||
|
class StorageAdapter extends Adapter
|
||||||
|
{
|
||||||
|
protected $config;
|
||||||
|
protected $db;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->config = Config::getInstance();
|
||||||
|
$this->db = Database::getInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
|
|
||||||
namespace Pickles;
|
namespace Pickles;
|
||||||
|
|
||||||
|
use \League\OAuth2\Server\ResourceServer;
|
||||||
|
use Pickles\OAuth2\AccessTokenStorage;
|
||||||
|
use Pickles\OAuth2\ClientStorage;
|
||||||
|
use Pickles\OAuth2\ScopeStorage;
|
||||||
|
use Pickles\OAuth2\SessionStorage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource Class
|
* Resource Class
|
||||||
*
|
*
|
||||||
|
@ -327,37 +333,6 @@ class Resource extends Object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create
|
|
||||||
public function POST()
|
|
||||||
{
|
|
||||||
// @todo Whatever gets POSTed (aside from OAuth stuff) should be inserted to the collection
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read
|
|
||||||
public function GET()
|
|
||||||
{
|
|
||||||
if (current($this->uids))
|
|
||||||
{
|
|
||||||
// @todo Pulls the record with this UID
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// @todo Do we pull all or return an empty set?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update
|
|
||||||
public function PUT()
|
|
||||||
{
|
|
||||||
// @todo If we have a UID, update the record with whatever is posted
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
public function DELETE()
|
|
||||||
{
|
|
||||||
// @todo If we have a UID, delete it
|
|
||||||
}
|
|
||||||
|
|
||||||
public function respond()
|
public function respond()
|
||||||
{
|
{
|
||||||
http_response_code($this->status);
|
http_response_code($this->status);
|
||||||
|
|
|
@ -54,7 +54,7 @@ class Router extends Object
|
||||||
$_SERVER['__version'] = substr($version, 1);
|
$_SERVER['__version'] = substr($version, 1);
|
||||||
|
|
||||||
// Checks if we're trying to rock some OAuth
|
// Checks if we're trying to rock some OAuth
|
||||||
if ($components[0] == 'oauth2')
|
if ($components[0] == 'oauth')
|
||||||
{
|
{
|
||||||
$class = 'Pickles\OAuth2\Resource';
|
$class = 'Pickles\OAuth2\Resource';
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,7 @@ class Router extends Object
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$nouns[] = $component;
|
$nouns[] = $component;
|
||||||
$uids[$component] = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue