zfcampus / zf-oauth2 Goto Github PK
View Code? Open in Web Editor NEWOAuth2 server module for ZF2
License: BSD 3-Clause "New" or "Revised" License
OAuth2 server module for ZF2
License: BSD 3-Clause "New" or "Revised" License
I'm using AngularJS with Apigility on an external domain and am unable to make authenticated ajax calls as the OPTIONS request doesn't return Access-Control-Allow-Headers: Authorization
in the response. This is causing AngularJS to not send the Authorization: Bearer {code}
. I had to add header('Access-Control-Allow-Headers: Authorization');
to the api, to get the browser to send the proper request cross-domain. Is there a way to tell Apigility to send this in the header for OPTION requests? Thanks.
In apigility you can specify optionally version in the url such as myapi.com/v2/myresource
however, this does not seem to work with the default /oauth
endpoint. myapi.com/v2/oauth
returns a 404. Is this intentional or do i need to look into my code to find the issue?
I'm working on creating a service with Apigility. This is my first time playing with zf-oauth2, so I might be missing something the rest of you think is obvious. Nonetheless, I can't find anything in the documentation on the proper format of the fields in the db. For example, how do I set up a client with both password AND refresh grant_types? I've tried separating them with commas, but that didn't work. I suppose semi-colon, colon, pipe, or some other character might work.
Also, why is the field for client_secret so damn long - varchar(2000) when it should cap out at 60 chars? (No?)
Thanks
I specify config:
'zf-oauth2' => array(
'db' => array(
'dsn' => 'mysql:dbname=name;host=localhost',
'username' => 'root',
'password' => NULL,
),
'options' => array(
'token_bearer_header_name' => 'bc',
'token_type' => 'bc',
),
'allow_implicit' => true,
'access_lifetime' => 3600,
'enforce_state' => true,
'storage' => 'ZF\OAuth2\Adapter\PdoAdapter',
'allow_public_clients' => true,
'always_issue_new_refresh_token' => true,
'storage_settings' => array(
'user_table' => 'user',
),
),
but ZF\Oauth returns the next:
{
"access_token":"5a27f4d2ec9a95b9088a99f483859339fa0ce1dc",
"expires_in":3600,
"token_type":"Bearer",
"scope":"token",
"refresh_token":"28cec2364fc7f3ac8168753179576386078aca5a"
}
Thanks for this great module, I just wanted to pin out 2 important things that were mssing in the documentation. At least it took me a while to find the missing pieces. Please can you add how to enable the modules:
config\application.config.php
'modules' => array(
...
'ZF\ApiProblem',
'ZF\ContentNegotiation',
'ZF\OAuth2'
),
Also it would have been nice if you had a curl example. It took me also some time to convert the httpie command into curl, could have been me, but it would be nice to have both options:
Here is the one I created:
curl -i -X POST --user testclient:testpass --data "grant_type=client_credentials" http:///oauth
Anyway thanks a lot
The code of PdoAdapter::setClientDetails refers to two columns not available: scope
and user_id
.
I'm a little confused if not concerned about how the zf-oauth2 module is suppose to be implemented in a ZF2 application.
I'm confused as to why user_id is being pulled from the query/request in the authorizeAction
of AuthController
.
As I understood the oauth client process some third party application of my ZF2 application would redirect the user to my application to authorize access. My ZF2 application would use its authentication state to identify the user (potentially requiring a log in) then once the user is authenticated present the user with an Authorize Third-party App prompt. My ZF2 application would then forward the user back to the third party application with a token identifying the user as an identity in my Application.
If user_id is a query parameter (rendered in the grant access form) a user could easily change the user_id value that was passed from the client to something else -- potentially a different user id.
When I was reading through the AuthController I was expecting to see the user id being pulled from an identity provided by the AuthenticationService (requiring zend-authentication module).
So I'm a little concerned right now about the security of this modules implementation. Is AuthController just a sample implementation? Or is there something I'm missing about how to use this server implementation that resolves the issue?
I'm using the Apigility skeleton application with bshaffer/oauth2-server-php version dev-develop. When I request a new token I don't get a JSON string but some HTML code with an error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'is_default' in 'where clause'
The problem seems to be with the vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php file at line 282 and the create statement for the oauth_scopes
table shown in the zf-oauth2 readme.
I tried adding the is_default
column in the oauth_scopes
and all seems ok:
ALTER TABLE `apigility`.`oauth_scopes` ADD COLUMN `is_default` TINYINT(1) NULL DEFAULT NULL;
Not sure if this belongs more in the underlying OAuth2 server project, but is there any need / reason to salt the BCrypted passwords?
Could that be enabled/disabled via config?
Your requirements could not be resolved to an installable set of packages.
Problem 1
- zfcampus/zf-oauth2 1.3.0 requires bshaffer/oauth2-server-php ~1.7 -> no matching package found.
- zfcampus/zf-oauth2 1.2.0 requires bshaffer/oauth2-server-php ~1.7 -> no matching package found.
- zfcampus/zf-oauth2 1.1.3 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.1.2 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.1.1 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.1.0 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.0.3 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.0.2 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.0.1 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.0.0 requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
- zfcampus/zf-oauth2 1.1.x-dev requires bshaffer/oauth2-server-php ~1.3 -> no matching package found.
I have just started a clean "install" of the 0.9.0 version of apigility and have tried to set up PDO-based OAuth2 authentication. I filled out the four fields and clicked on the Save button. Nothing happens.
Using Chrome, I opened up the developer tools window, selected the console tab, and noticed that the following error occurs when I click on the Save button:
An invalid form control with name='' is not focusable.
I don't recall trying this in previous versions, so I can't say whether or not it's worked before.
I think class ZF\OAuth2\Controller\AuthControllerFactory.php
is not used.
Instead is used ZF\OAuth2\Factory\AuthControllerFactory
as we can see in the module.config.php
'controllers' => array(
'factories' => array(
'ZF\OAuth2\Controller\Auth' => 'ZF\OAuth2\Factory\AuthControllerFactory',
),
),
Closed.
Hi,
simple question, what is the purpose of type
in oauth_scopes
? I saw that the default value is supported
should I consider that there is only 2 values : supported
/ unsupported
? or this field is free to fill?
Thank you ^^
PdoAdapter extends from bshaffer/oauth2-server-php storage PDO. :
Strict Standards: Declaration of ZF\OAuth2\Adapter\PdoAdapter::setClientDetails() should be compatible with OAuth2\Storage\Pdo::setClientDetails($client_id, $client_secret = NULL, $redirect_uri = NULL, $grant_types = NULL, $scope = NULL, $user_id = NULL)
they added the scope parameter in setClientDetails
When I attempt to run console based commands, I get the included error. I have been googling about to see if anyone has experienced something similar but cant seem to find a solution. I have checked my settings and everything appears in order and running normal routes works perfectly.
I am a little stumped as to how to bug test this further.
If I comment out: 'ZF\OAuth2', from application config, the error vanishes.
Any ideas?
Much appreciated.
PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] No such file or directory' in trunk/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php:53
Stack trace:
#0 /Applications/MAMP/htdocs/workspaces/trade/trunk/vendor/bshaffer/oauth2-server-php/src/OAuth2/Storage/Pdo.php(53): PDO->__construct('mysql:dbname=on...', 'root', 'root', Array)
#1 /Applications/MAMP/htdocs/workspaces/trade/trunk/vendor/zfcampus/zf-oauth2/src/Adapter/PdoAdapter.php(89): OAuth2\Storage\Pdo->__construct(Array, Array)
#2 /Applications/MAMP/htdocs/workspaces/trade/trunk/vendor/zfcampus/zf-oauth2/src/Factory/PdoAdapterFactory.php(45): ZF\OAuth2\Adapter\PdoAdapter->__construct(Array, Array)
#3 [internal function]: ZF\OAuth2\Factory\PdoAdapterFactory->createService(Object(Zend\ServiceManager\ServiceManager), 'zfoauth2adapter...', 'ZF\OAuth2\Adapt...')
#4 /Applications/MAMP/htdocs/workspaces/trade/trunk/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceM in /Applications/MAMP/htdocs/workspaces/trade/trunk/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php on line 930
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] No such file or directory' in /Applications/MAMP/htdocs/workspaces/trade/trunk/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php on line 930
When entering wrong OAuth2 details, apigility comes completely unuseable...
Admin and API are down :-/
Stacktrace:
Fatal error: Uncaught exception 'PDOException' with message 'invalid data source name' in C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php on line 900
PDOException: invalid data source name in C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\bshaffer\oauth2-server-php\src\OAuth2\Storage\Pdo.php on line 43
Call Stack:
0.0030 147432 1. {main}() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\public\index.php:0
0.0090 289312 2. Zend\Mvc\Application::init() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\public\index.php:38
0.1730 3405600 3. Zend\Mvc\Application->bootstrap() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php:254
0.2010 3838168 4. Zend\EventManager\EventManager->trigger() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php:156
0.2010 3838368 5. Zend\EventManager\EventManager->triggerListeners() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:207
0.2370 4357032 6. call_user_func() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
0.2370 4357048 7. ZF\MvcAuth\Module->onBootstrap() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
0.2490 4641952 8. Zend\ServiceManager\ServiceManager->get() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\Module.php:53
0.2490 4642640 9. Zend\ServiceManager\ServiceManager->create() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:504
0.2490 4642640 10. Zend\ServiceManager\ServiceManager->doCreate() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:564
0.2490 4642672 11. Zend\ServiceManager\ServiceManager->createFromFactory() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:604
0.2500 4661768 12. Zend\ServiceManager\ServiceManager->createServiceViaCallback() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:1023
0.2500 4662096 13. call_user_func() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:893
0.2500 4662120 14. ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory->createService() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:893
0.2500 4679616 15. ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory->createOauth2ServerFromConfig() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\src\ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory.php:35
0.2500 4679960 16. Zend\ServiceManager\ServiceManager->get() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\src\ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory.php:121
0.2510 4680520 17. Zend\ServiceManager\ServiceManager->create() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:504
0.2510 4680520 18. Zend\ServiceManager\ServiceManager->doCreate() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:564
0.2510 4680552 19. Zend\ServiceManager\ServiceManager->createFromFactory() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:604
0.2520 4686112 20. Zend\ServiceManager\ServiceManager->createServiceViaCallback() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:1023
0.2520 4686384 21. call_user_func() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:893
0.2520 4686408 22. ZF\OAuth2\Factory\PdoAdapterFactory->createService() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:893
0.2590 4822504 23. ZF\OAuth2\Adapter\PdoAdapter->__construct() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-oauth2\src\ZF\OAuth2\Factory\PdoAdapterFactory.php:38
0.2590 4822648 24. OAuth2\Storage\Pdo->__construct() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-oauth2\src\ZF\OAuth2\Adapter\PdoAdapter.php:30
0.2590 4823264 25. PDO->__construct() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\bshaffer\oauth2-server-php\src\OAuth2\Storage\Pdo.php:43
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "ZF\OAuth2\Adapter\PdoAdapter"; no instance returned in C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php on line 900
Call Stack:
0.0030 147432 1. {main}() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\public\index.php:0
0.0090 289312 2. Zend\Mvc\Application::init() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\public\index.php:38
0.1730 3405600 3. Zend\Mvc\Application->bootstrap() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php:254
0.2010 3838168 4. Zend\EventManager\EventManager->trigger() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php:156
0.2010 3838368 5. Zend\EventManager\EventManager->triggerListeners() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:207
0.2370 4357032 6. call_user_func() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
0.2370 4357048 7. ZF\MvcAuth\Module->onBootstrap() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
0.2490 4641952 8. Zend\ServiceManager\ServiceManager->get() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\Module.php:53
0.2490 4642640 9. Zend\ServiceManager\ServiceManager->create() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:504
0.2490 4642640 10. Zend\ServiceManager\ServiceManager->doCreate() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:564
0.2490 4642672 11. Zend\ServiceManager\ServiceManager->createFromFactory() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:604
0.2500 4661768 12. Zend\ServiceManager\ServiceManager->createServiceViaCallback() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:1023
0.2500 4662096 13. call_user_func() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:893
0.2500 4662120 14. ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory->createService() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:893
0.2500 4679616 15. ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory->createOauth2ServerFromConfig() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\src\ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory.php:35
0.2500 4679960 16. Zend\ServiceManager\ServiceManager->get() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\src\ZF\MvcAuth\Factory\DefaultAuthenticationListenerFactory.php:121
0.2510 4680520 17. Zend\ServiceManager\ServiceManager->create() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:504
0.2510 4680520 18. Zend\ServiceManager\ServiceManager->doCreate() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:564
0.2510 4680552 19. Zend\ServiceManager\ServiceManager->createFromFactory() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:604
0.2520 4686112 20. Zend\ServiceManager\ServiceManager->createServiceViaCallback() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:1023
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "ZF\MvcAuth\Authentication\DefaultAuthenticationListener"; no instance returned in C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php on line 900
Call Stack:
0.0030 147432 1. {main}() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\public\index.php:0
0.0090 289312 2. Zend\Mvc\Application::init() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\public\index.php:38
0.1730 3405600 3. Zend\Mvc\Application->bootstrap() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php:254
0.2010 3838168 4. Zend\EventManager\EventManager->trigger() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php:156
0.2010 3838368 5. Zend\EventManager\EventManager->triggerListeners() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:207
0.2370 4357032 6. call_user_func() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
0.2370 4357048 7. ZF\MvcAuth\Module->onBootstrap() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php:468
0.2490 4641952 8. Zend\ServiceManager\ServiceManager->get() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zfcampus\zf-mvc-auth\Module.php:53
0.2490 4642640 9. Zend\ServiceManager\ServiceManager->create() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:504
0.2490 4642640 10. Zend\ServiceManager\ServiceManager->doCreate() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:564
0.2490 4642672 11. Zend\ServiceManager\ServiceManager->createFromFactory() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:604
0.2500 4661768 12. Zend\ServiceManager\ServiceManager->createServiceViaCallback() C:\Data\Zend\Apache2\htdocs\services.prestagroup.com\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:1023
I've been trying to authenticate via "WEB-server application" scenario (PDO adapter), and all works well except of one thing, the user_id column doesn't get populated when refresh_tokens and authorization_codes are inserted into the DB.
It looks like that ->getQuery('user_id',null) doesn't return a user_id for cases mentioned above here, instead it returns null: https://github.com/zfcampus/zf-oauth2/blob/master/src/Controller/AuthController.php#L129
Is this normal behavior? If so, is there a way to set user_id from an event, when row is being inserted?
The authentication receive code page (/oauth/receivecode) has a parse error. Moreover the https method is fixed in the code, it should be checked against the real http protocol used.
Go to:
http://plt.personello.lan/admin#/global/authentication
Try to add an oauth2 Server.
DSN:
mysql:dbname=yourdb_secured_with_username_and_password;host=localhost;charset=utf8
I've added the username and password accordingly. I've used the /oauth path, too.
The webfrontend failed with a JS error.
I was able to track down the error to the authentication model:
/**
* Validate a DSN
*
* @param string $dsn
* @throws Exception\InvalidArgumentException on invalid DSN
*/
protected function validateDsn($dsn)
{
try {
new PDO($dsn);
} catch (PDOException $e) {
throw new Exception\InvalidArgumentException(sprintf('Invalid DSN "%s" provided', $dsn), 422);
}
}
This method is missing the username and password parameter for a mysql dsn
After commenting out this line
$this->validateDsn($data['dsn']);
in the create fuction all configs are written as expected.
Hi, when I use this module in Apigility I often need to retrieve access token to get a user_id. I was wondering if we could add a service/plugin to be able to easily get the token from ResourceListener.
eg:
<?php
namespace ZF\OAuth2\Service;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\ServiceManager\ServiceManager;
class OAuthService implements ServiceManagerAwareInterface
{
public function getToken()
{
$sm = $this->getServiceManager();
$config = $sm->get('Configuration');
$request = $sm->get('Request');
if ($request->getPost('access_token')) {
$accessToken = $request->getQuery('access_token');
} else {
list($tokenType, $accessToken) = explode(' ', $request->getServer()->HTTP_AUTHORIZATION);
}
$storage = $config['zf-oauth2']['storage'];
$token = $sm->get($storage)->getAccessToken($accessToken);
$token = (object) $token;
return $token;
}
public function getServiceManager()
{
return $this->serviceManager;
}
public function setServiceManager(ServiceManager $serviceManager)
{
$this->serviceManager = $serviceManager;
return $this;
}
}
Using a authorization_code
grant type:
http://<apigility URL>/oauth/authorize?response_type=code &client_id=testclient&redirect_uri=/oauth/receivecode&state=xyz&
[email protected]
The parameter user_id
is not store in DB table oauth_authorization_codes and then when request access code, the user_id
is not populated to table oauth_access_tokens
.
I think the issue could be that ZF\OAuth2\Controller\AuthController::authorizeAction()
when call $this->server->handleAuthorizeRequest()
isn't use the fourth parameter.
Thanks.
Download latest apigility and vagrant up. Create a DB in the Vagrant environment and create a PDO adapter for OAuth in Apigility Admin. Hit the OAuth api end point and you will get: "An exception was raised while creating "ZF\OAuth2\Controller\Auth"; no instance returned" Verified credentials are fine and can connect when instantiating an adapter manually.
Further more, you will also see an exception 'The storage configuration ['zf-oauth2']['storage'] for OAuth2 is missing' which is raised by OAuth2ServerFactory. However, Apigility admin no longer creates the configuration using that array structure.
I have implemented same OAuth2 library and had a problem with https://github.com/bshaffer/oauth2-server-php/blob/7d30ce7ab8655abba148062671fe3457f615c9e9/src/OAuth2/Request.php#L111
file_get_contents('php://input');
this can be called once so when PUT request called you cant get content in zend request object or here so how you solved this if you solved? I had to implement OAuth2\ResponseInterface
to solve this.
If any exception is thrown by bshaffer/oauth2-server-php methods, it is not get captured and only we see an exception was thrown in the php error log. We should capture all exceptions thrown by bshaffer/oauth2-server-php method calls and convert them into ApiProblemResponse.
Continuing the work of zfcampus/zf-oauth2-doctrine
the latest code implements the adapter through services of oauth2 in zf-mvc-auth. When an application is properly configured this module still insists on a valid $config['zf-oauth2']['storage']
entry. This should not be necessary when using a service based adapter.
For this global.php configuration:
return array(
'zf-mvc-auth' => array(
'authentication' => array(
'map' => array(
'DbApi\\V1' => 'oauth2_doctrine',
),
),
'authentication' => array(
'adapters' => array(
'oauth2_doctrine' => array(
'adapter' => 'ZF\\MvcAuth\\Authentication\\OAuth2Adapter',
'storage' => array(
'storage' => 'oauth2.doctrineadapter.default',
'route' => '/oauth',
),
),
),
),
),
'zf-oauth2' => array(
'allow_implicit' => false, // default (set to true when you need to support browser-based or mobile apps)
'access_lifetime' => 3600, // default (set a value in seconds for access tokens lifetime)
'enforce_state' => true, // default
// 'storage' => 'oauth2.doctrineadapter.default',
),
);
without a value for storage the title's exception is raised. This can be easily duplicated by cloning https://github.com/API-Skeletons/doctrine-skeleton and following the instructions in the README.md file.
Hi,
OAuth2 specification describe in point 5.2. response format for invalid request.
But in AuthController::tokenAction if status code is beetwen 400 and 500, we return reposne in problem+json format, not in format from specification. Why?
I know that client can recognize content-type of response, but many OAuth2 clients recognize format from specification.
There are several options we should set if we want the oauth server to work with json web tokens
'zf-oauth2' => [
'grant_types' => [
'jwt' => true,
],
'audience' => $_SERVER['HTTP_HOST'],
'options' => [
'use_jwt_access_tokens' => true,
]
]
use_jwt_access_tokens will make the token factory create JWT tokens.
The audience option is supposed to create tokens with the 'aud' set to that value. That way tokens received can be quickly discarded when they are asserted against the wrong server by accident (my understanding atleast). However it seems the for creation the client_id is used. And this validation will always fail.
Therefore the only way to get this to work is to set the audience to the client_id, and thus use the entire oauth server for only one client_id.
I'm not sure is this is a problem with Apigility or the OAuth2 server. I'll post an issue there too...
example request to /oauth and resulting JWT payload
http POST https://myserver/oauth client_id=plhw-client client_secret=XXX redirect_uri=http%3A%2F%2Flocalhost%3A4200 grant_type=authorization_code code=8ce459d24d231b0bce1645baa9d4e4044f549ad2
gets
{"access_token":"header.payload.signature","expires_in":3600,"token_type":"bearer","scope":"","refresh_token":"447ed3606ac2c04128346f406e0d1f7fbb90be43"}
manually decoding the payload will yield something like
{"jti":"e5424a45b467ad334df368b518028410997ae3d6","iss":"","aud":"plhw-client","sub":5,"exp":1432155489,"iat":1432151889,"token_type":"bearer","scope":""}
but to assert the JWT with will fail because;
a. the issuer is empty but is required
b. the audience is set to the client_id and not the audience in the configuration
http POST https://myserver/oauth grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer assertion= header.payload.signature
If I go to the sample /oauth/resource resource with an expired access token, I get a 401 "expired_token" message:
{
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
"title": "expired_token",
"status": 401,
"detail": "The access token provided has expired"
}
However, if I go to my own "authentication required" REST service with the same expired expired access token, I get a 403 "forbidden" message:
{
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
"title": "Forbidden",
"status": 403,
"detail": "Forbidden"
}
After some debugging, it seems that this is because the $response
object that was passed to OAuth2\Controller\ResourceController::verifyResourceRequest (and later on set to 401 in OAuth2\Controller\ResourceController::getAccessTokenData) is just ignored later on in ZF\MvcAuth\Authentication\DefaultAuthenticationListener::__invoke (line 174 onwards) and a GuestIdentity
is returned, causing the authentication to treat it as an un-authenticated request by a guest, and not as an expired_token request.
Currently, the MongoAdapter factory fetches the Mongo configuration information from the zf-oauth2 storage configuration, and then passes that configuration to the MongoAdapter -- and the parent class establishes the MongoClient. This makes re-use of the MongoClient difficult; you have one of two options:
$db
property (which is the MongoClient instance).Ideally, we should separate out the MongoClient creation into its own factory. This would allow aliasing to a separate factory for shared connections, if desired, or using a provided factory that pulls the connection data from the zf-oauth2 configuration.
Please note on line 55
if (is_object($identity)) {
if (property_exists($identity, $this->userId)) {
return $identity->{$this->$userId}; <<<-------- ***
}
Should read: return $identity->{$this->userId}
Found here: https://github.com/zfcampus/zf-oauth2/blob/master/src/Provider/UserId/AuthenticationService.php
Otherwise it will output:
Undefined variable: userId in /var/www/cloud/vendor/zfcampus/zf-oauth2/src/Provider/UserId/AuthenticationService.php on line 55
I notice by default the field username
is required for Apigility.
I'd instead like to change login from using username
field in the DB to email
.. if this is configurable, great! but I am not seeing it.
Installed Apigility beta 1, and followed the instructions on 'How to test OAuth2'.
When using the example from 'Authorize (Code)', and I get the page with message:
Do you want to authorize testclient?'
I click 'Yes', and get a database error:
SQLSTATE[42703]: Undefined column: 7 ERROR: column "id_token" of relation "oauth_authorization_codes" does not exist
LINE 1: ...client_id, user_id, redirect_uri, expires, scope, id_token) ...
After creating an 'id_token' column in the tabe oauth_authorization_codes the page works as expected.
My database is in Postgresql, and imported from the example sql-file in /data/db_oauth2.sql
(Which needed som minor adjustments to work with postgresql)
When using composer and --prefer-dist
option, composer will download zip file.
$ composer show -i zfcampus/zf-oauth2
name : zfcampus/zf-oauth2
descrip. : ZF2 module for implementing an OAuth2 server
keywords : api, framework, oauth2, zf2
versions : * 1.1.2
type : library
license : BSD 3-clause "New" or "Revised" License (BSD-3-Clause) (OSI approved) http://spdx.org/licenses/BSD-3-Clause#licenseText
source : [git] https://github.com/zfcampus/zf-oauth2.git d2545896b0c94f31db8111790763ef27cbdef1ad
dist : [zip] https://packages.zendframework.com/composer/zfcampus-zf-oauth2-d2545896b0c94f31db8111790763ef27cbdef1ad-zip-bb2d0d.zip 1.1.2
names : zfcampus/zf-oauth2
support
source : https://github.com/zfcampus/zf-oauth2/tree/1.1.2
issues : https://github.com/zfcampus/zf-oauth2/issues
...
Exactly this one: https://packages.zendframework.com/composer/zfcampus-zf-oauth2-d2545896b0c94f31db8111790763ef27cbdef1ad-zip-bb2d0d.zip It has two src dirs inside:
[.../vendor/zfcampus/zf-oauth2] $ ls src/
Adapter/ Controller/ ExceptionInterface.php Factory/ Provider/ src/
[.../vendor/zfcampus/zf-oauth2] $ ls src/src/
Adapter/ Controller/ ExceptionInterface.php Factory/ Provider/
because of it, composer's optimizer shows some warnings:
Warning: Ambiguous class resolution, "ZF\OAuth2\Provider\UserId\AuthenticationServiceFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Provider/UserId/AuthenticationServiceFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Provider/UserId/AuthenticationServiceFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Provider\UserId\UserIdProviderInterface" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Provider/UserId/UserIdProviderInterface.php" and ".../vendor/zfcampus/zf-oauth2/src/Provider/UserId/UserIdProviderInterface.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Provider\UserId\Request" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Provider/UserId/Request.php" and ".../vendor/zfcampus/zf-oauth2/src/Provider/UserId/Request.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Provider\UserId\AuthenticationService" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Provider/UserId/AuthenticationService.php" and ".../vendor/zfcampus/zf-oauth2/src/Provider/UserId/AuthenticationService.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Factory\MongoAdapterFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Factory/MongoAdapterFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Factory/MongoAdapterFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Factory\OAuth2ServerFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Factory/OAuth2ServerFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Factory/OAuth2ServerFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Factory\PdoAdapterFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Factory/PdoAdapterFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Factory/PdoAdapterFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Factory\OAuth2ServerInstanceFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Factory/OAuth2ServerInstanceFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Factory/OAuth2ServerInstanceFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Factory\IbmDb2AdapterFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Factory/IbmDb2AdapterFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Factory/IbmDb2AdapterFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Factory\AuthControllerFactory" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Factory/AuthControllerFactory.php" and ".../vendor/zfcampus/zf-oauth2/src/Factory/AuthControllerFactory.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Controller\AuthController" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Controller/AuthController.php" and ".../vendor/zfcampus/zf-oauth2/src/Controller/AuthController.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Controller\Exception\RuntimeException" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Controller/Exception/RuntimeException.php" and ".../vendor/zfcampus/zf-oauth2/src/Controller/Exception/RuntimeException.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Controller\Exception\ExceptionInterface" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Controller/Exception/ExceptionInterface.php" and ".../vendor/zfcampus/zf-oauth2/src/Controller/Exception/ExceptionInterface.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\ExceptionInterface" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/ExceptionInterface.php" and ".../vendor/zfcampus/zf-oauth2/src/ExceptionInterface.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Adapter\IbmDb2Adapter" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Adapter/IbmDb2Adapter.php" and ".../vendor/zfcampus/zf-oauth2/src/Adapter/IbmDb2Adapter.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Adapter\BcryptTrait" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Adapter/BcryptTrait.php" and ".../vendor/zfcampus/zf-oauth2/src/Adapter/BcryptTrait.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Adapter\PdoAdapter" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Adapter/PdoAdapter.php" and ".../vendor/zfcampus/zf-oauth2/src/Adapter/PdoAdapter.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Adapter\MongoAdapter" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Adapter/MongoAdapter.php" and ".../vendor/zfcampus/zf-oauth2/src/Adapter/MongoAdapter.php", the first will be used.
Warning: Ambiguous class resolution, "ZF\OAuth2\Adapter\Exception\RuntimeException" was found in both ".../vendor/zfcampus/zf-oauth2/src/src/Adapter/Exception/RuntimeException.php" and ".../vendor/zfcampus/zf-oauth2/src/Adapter/Exception/RuntimeException.php", the first will be used.
Nothing critical in fact, but looks bad, could you fix it?
The ZF\OAuth2\Factory\OAuth2ServerFactory
is no longer returning a OAuth2\Server
instance?
https://github.com/zfcampus/zf-oauth2/blob/master/src/Factory/OAuth2ServerFactory.php
The file has been changed in the latest version and it returns a closure (Factory!?) now. My code is broken since I simply used $serviceLocator->get('ZF\OAuth2\Service\OAuth2Server');
elsewhere to get the OAuth2\Server
instance from the server manager.
The documentation has also not been updated accordingly and is no longer up to date since it still states it will give me an OAuth\Server
.
Is returning another factory from a factory really the way to go? How should I now get my oauth server instance? Is it maybe possible to separate the keys so getting the server is still possible?
Hey,
After updating to Apigility 1.1.1, oauth2 doesn't work anymore as expected.
I use oauth2 to authenticate as mentioned in documentation.
Following case:
Post to end-point with bearer return works, but now when i use this bearer to authenticate it doesn't work, it results in 401 forbidden or $this->getEvent()->getParam('ZF\\MvcAuth\\Identity')->getRoleId()
-> guest.
So changed there something? I noticed that it is now possible to add more than one authentication adapter. Unfortunately, documentation seems to be outdated.
thanks for help
ternes3
Hello
I think there is a problem with Username and password access.
I make tthis to get a token:
POST /oauth HTTP/1.1
Accept: application/json
Authorization: Basic dGVzdGNsaWVudDp0ZXN0cGFzcw==
Content-Type: application/json
{
"grant_type": "password",
"username": "testuser",
"password": "testpass"
}
It work both and return token with or without password !
Maybe I miss something ?
Best regards
Jérôme
Today I updated to the latest dev version. I do not use the oauth adapter and do not have the oauth configuration in mij config files.
While calling the webservice I retrieve following exception:
Uncaught exception 'ZF\OAuth2\Controller\Exception\RuntimeException' with message 'The database configuration ['zf-oauth2']['db'] for OAuth2 is missing
This exception should not be thrown, because I do not need the oauth adapter. Maybe this adapter should be loaded lazily?
I get this error when i try to install through composer:
Problem 1
- Installation request for zfcampus/zf-oauth2 1.0.*@dev -> satisfiable by zfcampus/zf-oauth2[1.0.x-dev].
- zfcampus/zf-oauth2 1.0.x-dev requires zendframework/zendframework ~2.3-dev -> no matching package found.
I'm using ZF version 2.2.* (from the skeleton app) but you have 2.3-dev in your composer.json file. Why not use the current stable version? Or have i just misunderstood something?
I have a problem. when i'm creating a Mongo oAuth2 adapter in Apigility admin panel i got 500 Internal Server Error
Request to /apigility/api/authentication/oauth2, json {database: "mongo_test" dsn_type: "Mongo" route_match: "/oauth"}
Error is Fatal error: Call to a member function isOAuth2() on a non-object in /path/vendor/zfcampus/zf-apigility-admin/src/Model/AuthenticationModel.php on line 53
How to fix this?
I have added this line into file composer.json
"zfcampus/zf-oauth2": "0.7.0"
then run php composer.phar install
but i got error that there is no package bshaffer/oauth2-server-php
https://github.com/zfcampus/zf-oauth2/blob/master/src/Factory/OAuth2ServerFactory.php#L76
Server instances are missing a grantTypes
param, meaning that overriding isn't possible without replacing the factory completely.
I followed the readme and i am able to generate the authorize code but when i try to use the authorize code to generate the token i get the following error:
$ curl -u testclient:testpass http://tracker.jaavi.dev/oauth -d 'grant_type=aut
horization_code&code=4c57461be5f5af65f472260a9b46e18ac02446a0&redirect_uri=/oau
th/receivecode' -v
* Trying 192.168.56.95...
* Connected to tracker.jaavi.dev (192.168.56.95) port 80 (#0)
* Server auth using Basic with user 'testclient'
> POST /oauth HTTP/1.1
> Authorization: Basic dGVzdGNsaWVudDp0ZXN0cGFzcw==
> User-Agent: curl/7.41.0
> Host: tracker.jaavi.dev
> Accept: */*
> Content-Length: 133
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 133 out of 133 bytes
< HTTP/1.1 400 invalid_client
< Date: Fri, 03 Jul 2015 17:49:53 GMT
< Server: Apache/2.4.10 (Debian)
< Connection: close
< Transfer-Encoding: chunked
< Content-Type: application/problem+json
<
{"type":"http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html","title":"invali
d_client","status":400,"detail":"Client credentials were not found in the header
s or body"}* Closing connection 0
Why is the factory $this->getServiceLocator()->get('ZF\OAuth2\Service\OAuth2Server') returns object ZF\OAuth2\Factory\OAuth2ServerInstanceFactory and an error occurs: "ZF\OAuth2\Factory\OAuth2ServerInstanceFactory::verifyResourceRequest()".
Examining the code, I tried to do $this->server()->verifyResourceRequest() and I get error 500.
SOLVED: I'am replace $this->server on $server, and call $server()->verifyResourceRequest(). It work.
The phtml does not render error after clicking NO.
oauth/receivecode?error=access_denied&error_description=The+user+denied+access+to+your+application&state=xyz
How to use refresh token.
is there any client side implementation? thanks
How can I use refresh tokens? I can't find anything on the wiki.
I'm trying to set the always_issue_new_refresh_token option to true in my zf-oauth2 configuration:
'zf-oauth2' => [
'options' => [
'always_issue_new_refresh_token' => true,
]
],
But I get the following error:
Uncaught exception 'MongoConnectionException' with message '- Found unknown connection string option 'always_issue_new_refresh_token' with value '1''
It seems that the options parameters are passed as the second argument of MongoClient, that behavior was updated with the PR#64. I couldn't find any workaround for this config, so I believe there should be an additional parameter inside options to pass the MongoClient specific configurations.
Hello,
I am new to OAuth2 and am putting together my first app with ApiGility/ZF2. Where I am struggling is with my understanding of the various database tables. I am not sure where to store what. For instance http://coop.apps.knpuniversity.com has all the basic items, although the tutorial is for the user of the API and not for putting together the nuts and bolts of an app offering the API. I have however got some insight into how this should work.
So for instance:
I want to be able to give clients access to my app. To do this an admin or a client may log in and setup an account, this account will be given access to the various end points as created in apiGility.
Step 1 is to create a unique client id which I do as such: $this->oAuthPdo->setClientDetails('testclient','$2y$14$f3qml4G2hG6sxM26VMq.geDYbsS089IBtVJ7DlD05BoViS9PFykE2','/oauth/receivecode');
This stores the details in the: oauth_clients table
From what I understand from the coop.app I can create scopes and link these scopes to a client. So my question is, how do I use oauth_scopes to limit the end points available to a client?
Many thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.