From 7d0c1bb737f3683cd770ebd757d938f39a9b55ef Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Sun, 18 Feb 2018 20:24:41 -0500 Subject: Created test vehicle module oauth2test --- Zotlabs/Module/Oauth2test.php | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Zotlabs/Module/Oauth2test.php (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Oauth2test.php b/Zotlabs/Module/Oauth2test.php new file mode 100644 index 000000000..14aa6137a --- /dev/null +++ b/Zotlabs/Module/Oauth2test.php @@ -0,0 +1,43 @@ + z_root(), + '$endpoints' => array( + array( + 'oauth2test', + array( + array( + 'action', 'create_db' + ) + ), + 'oauth2test_create_db', + 'Create the OAuth2 database tables' + ) + ) + )); + + return $o; + } + + function post() { + + logger(json_encode($_POST), LOGGER_DEBUG); + + switch ($_POST['action']) { + case 'create_db': + logger('Creating database tables...', LOGGER_DEBUG); + break; + + default: + break; + } + + } + +} -- cgit v1.2.3 From 89a825cd038df7da609d64ef0254ba58caaede31 Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Tue, 20 Feb 2018 21:11:38 -0500 Subject: OAuth2TestVehicle module can create and delete oauth2 database tables. --- Zotlabs/Module/Oauth2test.php | 43 -------------- Zotlabs/Module/Oauth2testvehicle.php | 107 +++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 43 deletions(-) delete mode 100644 Zotlabs/Module/Oauth2test.php create mode 100644 Zotlabs/Module/Oauth2testvehicle.php (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Oauth2test.php b/Zotlabs/Module/Oauth2test.php deleted file mode 100644 index 14aa6137a..000000000 --- a/Zotlabs/Module/Oauth2test.php +++ /dev/null @@ -1,43 +0,0 @@ - z_root(), - '$endpoints' => array( - array( - 'oauth2test', - array( - array( - 'action', 'create_db' - ) - ), - 'oauth2test_create_db', - 'Create the OAuth2 database tables' - ) - ) - )); - - return $o; - } - - function post() { - - logger(json_encode($_POST), LOGGER_DEBUG); - - switch ($_POST['action']) { - case 'create_db': - logger('Creating database tables...', LOGGER_DEBUG); - break; - - default: - break; - } - - } - -} diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/Oauth2testvehicle.php new file mode 100644 index 000000000..2a2590928 --- /dev/null +++ b/Zotlabs/Module/Oauth2testvehicle.php @@ -0,0 +1,107 @@ + z_root(), + /* + endpoints => array( + array( + 'path_to_endpoint', + array( + array('field_name_1', 'value'), + array('field_name_2', 'value'), + ... + ), + 'submit_button_name', + 'Description of API action' + ) + ) + */ + '$endpoints' => array( + array( + 'oauth2testvehicle', + array( + array( + 'action', 'create_db' + ) + ), + 'oauth2test_create_db', + 'Create the OAuth2 database tables' + ), + array( + 'oauth2testvehicle', + array( + array( + 'action', 'delete_db' + ) + ), + 'oauth2test_delete_db', + 'Delete the OAuth2 database tables' + ) + ) + )); + + return $o; + } + + function post() { + + logger(json_encode($_POST), LOGGER_DEBUG); + + switch ($_POST['action']) { + + case 'delete_db': + $status = true; + // Use the \OAuth2\Storage\Pdo class to create the OAuth2 tables + // by passing it the database connection + $pdo = \DBA::$dba->db; + $storage = new \Zotlabs\Storage\ZotOauth2Pdo($pdo); + logger('Deleting existing database tables...', LOGGER_DEBUG); + foreach ($storage->getConfig() as $key => $table) { + logger('Deleting table ' . dbesc($table), LOGGER_DEBUG); + $r = q("DROP TABLE IF EXISTS %s;", dbesc($table)); + if (!$r) { + logger('Errors encountered deleting database table ' . $table . '.', LOGGER_DEBUG); + $status = false; + } + } + if (!$status) { + notice('Errors encountered deleting database tables.' . EOL); + } else { + info('Database tables deleted successfully.' . EOL); + } + + break; + + case 'create_db': + $status = true; + logger('Creating database tables...', LOGGER_DEBUG); + @include('.htconfig.php'); + $pdo = \DBA::$dba->db; + $storage = new \Zotlabs\Storage\ZotOauth2Pdo($pdo); + foreach (explode(';', $storage->getBuildSql($db_data)) as $statement) { + try { + $result = $pdo->exec($statement); + } catch (\PDOException $e) { + $status = false; + logger('Error executing database statement: ' . $statement, LOGGER_DEBUG); + } + } + + if (!$status) { + notice('Errors encountered creating database tables.' . EOL); + } else { + info('Database tables created successfully.' . EOL); + } + + default: + break; + } + } + +} -- cgit v1.2.3 From 43fca182e3915734587abf389d819546ebade3a4 Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Thu, 22 Feb 2018 15:10:05 -0500 Subject: The authorization step with client registration and authorization code retrieval working. Might not conform perfectly to OAuth2 spec, but it is a start. --- Zotlabs/Module/Authorize.php | 79 +++++++++++++++++++++++++++--------- Zotlabs/Module/Oauth2testvehicle.php | 56 ++++++++++++++++++------- 2 files changed, 100 insertions(+), 35 deletions(-) (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php index 254700b4e..f98453fb5 100644 --- a/Zotlabs/Module/Authorize.php +++ b/Zotlabs/Module/Authorize.php @@ -4,15 +4,14 @@ namespace Zotlabs\Module; use Zotlabs\Identity\OAuth2Storage; - class Authorize extends \Zotlabs\Web\Controller { function init() { // workaround for HTTP-auth in CGI mode if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { - $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; - if(strlen($userpass)) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); + if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; $_SERVER['PHP_AUTH_PW'] = $password; @@ -20,43 +19,83 @@ class Authorize extends \Zotlabs\Web\Controller { } if (x($_SERVER, 'HTTP_AUTHORIZATION')) { - $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; - if(strlen($userpass)) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)); + if (strlen($userpass)) { list($name, $password) = explode(':', $userpass); $_SERVER['PHP_AUTH_USER'] = $name; $_SERVER['PHP_AUTH_PW'] = $password; } } + } + + function get() { + if (!local_channel()) { + return login(); + } else { + // display an authorization form + $app = array('name' => 'Test App', 'icon' => '/images/icons/plugin.png'); + $o .= replace_macros(get_markup_template('oauth_authorize.tpl'), array( + '$title' => '', + '$authorize' => 'Do you authorize the app "' . $app['name'] . '" to access your channel data?', + '$app' => $app, + '$yes' => t('Allow'), + '$no' => t('Deny'), + '$client_id' => (x($_REQUEST, 'client_id') ? $_REQUEST['client_id'] : ''), + '$redirect_uri' => (x($_REQUEST, 'redirect_uri') ? $_REQUEST['redirect_uri'] : ''), + '$state' => (x($_REQUEST, 'state') ? $_REQUEST['state'] : '') + )); + return $o; + } + } + + function post() { + if (!local_channel()) { + return $this->get(); + } + + $storage = new OAuth2Storage(\DBA::$dba->db); + $s = new \Zotlabs\Identity\OAuth2Server($storage); + + + // If no client_id was provided, generate a new one. + if (x($_POST, 'client_id')) { + $client_id = $_POST['client_id']; + logger('client_id was provided: ' . $client_id); + } else { + $client_id = $_POST['client_id'] = random_string(16); + logger('client_id was not provided. Generated new id: ' . $client_id); + } + // If no redirect_uri was provided, generate a fake one. + if (x($_POST, 'redirect_uri')) { + $redirect_uri = $_POST['redirect_uri']; + } else { + $redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com'; + } - $s = new \Zotlabs\Identity\OAuth2Server(new OAuth2Storage(\DBA::$dba->db)); + logger('redirect_uri is : ' . $redirect_uri); + // If the client is not registered, add to the database + if (!$storage->getClientDetails($client_id)) { + $client_secret = random_string(16); + $storage->setClientDetails($client_id, $client_secret, $redirect_uri); + } $request = \OAuth2\Request::createFromGlobals(); + logger(json_encode($request, JSON_PRETTY_PRINT), LOGGER_DEBUG); $response = new \OAuth2\Response(); // validate the authorize request - if (! $s->validateAuthorizeRequest($request, $response)) { + if (!$s->validateAuthorizeRequest($request, $response)) { $response->send(); killme(); } - // display an authorization form - if (empty($_POST)) { - - return ' -
-
- - -
'; - } - // print the authorization code if the user has authorized your client - $is_authorized = ($_POST['authorized'] === 'yes'); + $is_authorized = ($_POST['authorize'] === 'allow'); $s->handleAuthorizeRequest($request, $response, $is_authorized, local_channel()); if ($is_authorized) { // this is only here so that you get to see your code in the cURL request. Otherwise, // we'd redirect back to the client - $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=')+5, 40); + $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40); echo("SUCCESS! Authorization Code: $code"); } diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/Oauth2testvehicle.php index 2a2590928..6e9f31c47 100644 --- a/Zotlabs/Module/Oauth2testvehicle.php +++ b/Zotlabs/Module/Oauth2testvehicle.php @@ -4,23 +4,34 @@ namespace Zotlabs\Module; class OAuth2TestVehicle extends \Zotlabs\Web\Controller { + function init() { + + // If there is a 'code' and 'state' parameter then this is a client app + // callback issued after the authorization code request + if ($_REQUEST['code'] && $_REQUEST['state']) { + logger('Authorization callback invoked.', LOGGER_DEBUG); + logger(json_encode($_REQUEST, JSON_PRETTY_PRINT), LOGGER_DEBUG); + info('Authorization callback invoked.' . EOL); + return $this->get(); + } + } function get() { $o .= replace_macros(get_markup_template('oauth2testvehicle.tpl'), array( '$baseurl' => z_root(), /* - endpoints => array( + endpoints => array( + array( + 'path_to_endpoint', array( - 'path_to_endpoint', - array( - array('field_name_1', 'value'), - array('field_name_2', 'value'), - ... - ), - 'submit_button_name', - 'Description of API action' + array('field_name_1', 'value'), + array('field_name_2', 'value'), + ... + ), + 'submit_button_name', + 'Description of API action' + ) ) - ) */ '$endpoints' => array( array( @@ -31,7 +42,8 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { ) ), 'oauth2test_create_db', - 'Create the OAuth2 database tables' + 'Create the OAuth2 database tables', + 'POST' ), array( 'oauth2testvehicle', @@ -41,7 +53,20 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { ) ), 'oauth2test_delete_db', - 'Delete the OAuth2 database tables' + 'Delete the OAuth2 database tables', + 'POST' + ), + array( + 'authorize', + array( + array('response_type', 'code'), + array('client_id', urlencode('test_app_client_id')), + array('redirect_uri', urlencode('http://hub.localhost/oauth2testvehicle')), + array('state', 'xyz') + ), + 'oauth_authorize', + 'Authorize a test client app', + 'GET' ) ) )); @@ -53,8 +78,9 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { logger(json_encode($_POST), LOGGER_DEBUG); + switch ($_POST['action']) { - + case 'delete_db': $status = true; // Use the \OAuth2\Storage\Pdo class to create the OAuth2 tables @@ -64,7 +90,7 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { logger('Deleting existing database tables...', LOGGER_DEBUG); foreach ($storage->getConfig() as $key => $table) { logger('Deleting table ' . dbesc($table), LOGGER_DEBUG); - $r = q("DROP TABLE IF EXISTS %s;", dbesc($table)); + $r = q("DROP TABLE %s;", dbesc($table)); if (!$r) { logger('Errors encountered deleting database table ' . $table . '.', LOGGER_DEBUG); $status = false; @@ -77,7 +103,7 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { } break; - + case 'create_db': $status = true; logger('Creating database tables...', LOGGER_DEBUG); -- cgit v1.2.3 From 64ee42fc3d00765bc5c60e451b86230ea38ffdfb Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Sat, 24 Feb 2018 06:48:30 -0500 Subject: Add channel ID to user_id in clients table. Added TODO comments about dynamic client registration protocol. --- Zotlabs/Module/Authorize.php | 27 +++++++++++++++++---------- Zotlabs/Module/Oauth2testvehicle.php | 11 +++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php index f98453fb5..2c0c9248f 100644 --- a/Zotlabs/Module/Authorize.php +++ b/Zotlabs/Module/Authorize.php @@ -32,17 +32,23 @@ class Authorize extends \Zotlabs\Web\Controller { if (!local_channel()) { return login(); } else { - // display an authorization form - $app = array('name' => 'Test App', 'icon' => '/images/icons/plugin.png'); + // TODO: Fully implement the dynamic client registration protocol: + // OpenID Connect Dynamic Client Registration 1.0 Client Metadata + // http://openid.net/specs/openid-connect-registration-1_0.html + $app = array( + 'name' => (x($_REQUEST, 'client_name') ? urldecode($_REQUEST['client_name']) : 'Unknown App'), + 'icon' => (x($_REQUEST, 'logo_uri') ? urldecode($_REQUEST['logo_uri']) : '/images/icons/plugin.png'), + 'url' => (x($_REQUEST, 'client_uri') ? urldecode($_REQUEST['client_uri']) : ''), + ); $o .= replace_macros(get_markup_template('oauth_authorize.tpl'), array( '$title' => '', - '$authorize' => 'Do you authorize the app "' . $app['name'] . '" to access your channel data?', + '$authorize' => 'Do you authorize the app ' . $app['name'] . ' to access your channel data?', '$app' => $app, '$yes' => t('Allow'), '$no' => t('Deny'), '$client_id' => (x($_REQUEST, 'client_id') ? $_REQUEST['client_id'] : ''), '$redirect_uri' => (x($_REQUEST, 'redirect_uri') ? $_REQUEST['redirect_uri'] : ''), - '$state' => (x($_REQUEST, 'state') ? $_REQUEST['state'] : '') + '$state' => (x($_REQUEST, 'state') ? $_REQUEST['state'] : ''), )); return $o; } @@ -56,14 +62,15 @@ class Authorize extends \Zotlabs\Web\Controller { $storage = new OAuth2Storage(\DBA::$dba->db); $s = new \Zotlabs\Identity\OAuth2Server($storage); - + // TODO: The automatic client registration protocol below should adhere more + // closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined + // at https://tools.ietf.org/html/rfc7591 + // If no client_id was provided, generate a new one. if (x($_POST, 'client_id')) { $client_id = $_POST['client_id']; - logger('client_id was provided: ' . $client_id); } else { $client_id = $_POST['client_id'] = random_string(16); - logger('client_id was not provided. Generated new id: ' . $client_id); } // If no redirect_uri was provided, generate a fake one. if (x($_POST, 'redirect_uri')) { @@ -72,15 +79,15 @@ class Authorize extends \Zotlabs\Web\Controller { $redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com'; } - logger('redirect_uri is : ' . $redirect_uri); // If the client is not registered, add to the database if (!$storage->getClientDetails($client_id)) { $client_secret = random_string(16); - $storage->setClientDetails($client_id, $client_secret, $redirect_uri); + // Client apps are registered per channel + $user_id = local_channel(); + $storage->setClientDetails($client_id, $client_secret, $redirect_uri, null, null, $user_id); } $request = \OAuth2\Request::createFromGlobals(); - logger(json_encode($request, JSON_PRETTY_PRINT), LOGGER_DEBUG); $response = new \OAuth2\Response(); // validate the authorize request diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/Oauth2testvehicle.php index 6e9f31c47..79958f025 100644 --- a/Zotlabs/Module/Oauth2testvehicle.php +++ b/Zotlabs/Module/Oauth2testvehicle.php @@ -8,6 +8,7 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { // If there is a 'code' and 'state' parameter then this is a client app // callback issued after the authorization code request + // TODO: Check state value and compare to original sent value if ($_REQUEST['code'] && $_REQUEST['state']) { logger('Authorization callback invoked.', LOGGER_DEBUG); logger(json_encode($_REQUEST, JSON_PRETTY_PRINT), LOGGER_DEBUG); @@ -61,8 +62,14 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { array( array('response_type', 'code'), array('client_id', urlencode('test_app_client_id')), - array('redirect_uri', urlencode('http://hub.localhost/oauth2testvehicle')), - array('state', 'xyz') + array('redirect_uri', 'http://hub.localhost/oauth2testvehicle'), + array('state', 'xyz'), + // OpenID Connect Dynamic Client Registration 1.0 Client Metadata + // http://openid.net/specs/openid-connect-registration-1_0.html + array('client_name', urlencode('Killer App')), + array('logo_uri', urlencode('https://client.example.com/website/img/icon.png')), + array('client_uri', urlencode('https://client.example.com/website')), + array('application_type', 'web'), // would be 'native' for mobile app ), 'oauth_authorize', 'Authorize a test client app', -- cgit v1.2.3 From 70b8f3240f9bc38a41e314f613f6c1bd69f5b430 Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Sun, 25 Feb 2018 08:36:40 -0500 Subject: An authorization token is received, but I had to modify the Request class in vendor/bshaffer/oauth2-server-php/ to accept $_REQUEST instead of $_POST. --- Zotlabs/Module/Authorize.php | 9 ++--- Zotlabs/Module/Oauth2testvehicle.php | 66 ++++++++++++++++++++++++++++++------ Zotlabs/Module/Token.php | 3 +- 3 files changed, 63 insertions(+), 15 deletions(-) (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php index 2c0c9248f..f505b4681 100644 --- a/Zotlabs/Module/Authorize.php +++ b/Zotlabs/Module/Authorize.php @@ -79,17 +79,18 @@ class Authorize extends \Zotlabs\Web\Controller { $redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com'; } + $request = \OAuth2\Request::createFromGlobals(); + $response = new \OAuth2\Response(); + // If the client is not registered, add to the database if (!$storage->getClientDetails($client_id)) { $client_secret = random_string(16); // Client apps are registered per channel $user_id = local_channel(); - $storage->setClientDetails($client_id, $client_secret, $redirect_uri, null, null, $user_id); + $storage->setClientDetails($client_id, $client_secret, $redirect_uri, 'authorization_code', null, $user_id); + $response->setParameter('client_secret', $client_secret); } - $request = \OAuth2\Request::createFromGlobals(); - $response = new \OAuth2\Response(); - // validate the authorize request if (!$s->validateAuthorizeRequest($request, $response)) { $response->send(); diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/Oauth2testvehicle.php index 79958f025..37a0b9b0e 100644 --- a/Zotlabs/Module/Oauth2testvehicle.php +++ b/Zotlabs/Module/Oauth2testvehicle.php @@ -9,6 +9,11 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { // If there is a 'code' and 'state' parameter then this is a client app // callback issued after the authorization code request // TODO: Check state value and compare to original sent value + // "You should first compare this state value to ensure it matches the + // one you started with. You can typically store the state value in a + // cookie, and compare it when the user comes back. This ensures your + // redirection endpoint isn't able to be tricked into attempting to + // exchange arbitrary authorization codes." if ($_REQUEST['code'] && $_REQUEST['state']) { logger('Authorization callback invoked.', LOGGER_DEBUG); logger(json_encode($_REQUEST, JSON_PRETTY_PRINT), LOGGER_DEBUG); @@ -39,29 +44,29 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { 'oauth2testvehicle', array( array( - 'action', 'create_db' + 'action', 'delete_db' ) ), - 'oauth2test_create_db', - 'Create the OAuth2 database tables', + 'oauth2test_delete_db', + 'Delete the OAuth2 database tables', 'POST' ), array( 'oauth2testvehicle', array( array( - 'action', 'delete_db' + 'action', 'create_db' ) ), - 'oauth2test_delete_db', - 'Delete the OAuth2 database tables', + 'oauth2test_create_db', + 'Create the OAuth2 database tables', 'POST' ), array( 'authorize', array( array('response_type', 'code'), - array('client_id', urlencode('test_app_client_id')), + array('client_id', urlencode('killer_app')), array('redirect_uri', 'http://hub.localhost/oauth2testvehicle'), array('state', 'xyz'), // OpenID Connect Dynamic Client Registration 1.0 Client Metadata @@ -74,6 +79,27 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { 'oauth_authorize', 'Authorize a test client app', 'GET' + ), + /* + * POST https://api.authorization-server.com/token + grant_type=authorization_code& + code=AUTH_CODE_HERE& + redirect_uri=REDIRECT_URI& + client_id=CLIENT_ID + */ + array( + 'oauth2testvehicle', + array( + array('action', 'request_token'), + array('grant_type', 'authorization_code'), + array('code', (x($_REQUEST, 'code') ? $_REQUEST['code'] : 'no_authorization_code')), + array('redirect_uri', 'http://hub.localhost/oauth2testvehicle'), + array('client_id', urlencode('killer_app')), + array('client_secret', (x($_REQUEST, 'client_secret') ? $_REQUEST['client_secret'] : 'no_client_secret')), + ), + 'oauth_token_request', + 'Request a token', + 'POST' ) ) )); @@ -83,11 +109,31 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { function post() { - logger(json_encode($_POST), LOGGER_DEBUG); - + //logger(json_encode($_POST, JSON_PRETTY_PRINT), LOGGER_DEBUG); switch ($_POST['action']) { - + case 'request_token': + $grant_type = (x($_POST, 'grant_type') ? $_POST['grant_type'] : ''); + $redirect_uri = (x($_POST, 'redirect_uri') ? $_POST['redirect_uri'] : ''); + $client_id = (x($_POST, 'client_id') ? $_POST['client_id'] : ''); + $code = (x($_POST, 'code') ? $_POST['code'] : ''); + $client_secret = (x($_POST, 'client_secret') ? $_POST['client_secret'] : ''); + $url = z_root() . '/token/?'; + $url .= 'grant_type=' . urlencode($grant_type); + $url .= '&redirect_uri=' . urlencode($redirect_uri); + $url .= '&client_id=' . urlencode($client_id); + $url .= '&code=' . urlencode($code); + $post = z_fetch_url($url, false, 0, array( + 'custom' => 'POST', + 'http_auth' => $client_id . ':' . $client_secret, + )); + //logger(json_encode($post, JSON_PRETTY_PRINT), LOGGER_DEBUG); + $response = json_decode($post['body'], true); + logger(json_encode($response, JSON_PRETTY_PRINT), LOGGER_DEBUG); + if($response['access_token']) { + info('Access token received: ' . $response['access_token'] . EOL); + } + break; case 'delete_db': $status = true; // Use the \OAuth2\Storage\Pdo class to create the OAuth2 tables diff --git a/Zotlabs/Module/Token.php b/Zotlabs/Module/Token.php index f7c074233..32cf95c61 100644 --- a/Zotlabs/Module/Token.php +++ b/Zotlabs/Module/Token.php @@ -29,7 +29,8 @@ class Token extends \Zotlabs\Web\Controller { } $s = new \Zotlabs\Identity\OAuth2Server(new OAuth2Storage(\DBA::$dba->db)); - $s->handleTokenRequest(\OAuth2\Request::createFromGlobals())->send(); + $request = \OAuth2\Request::createFromGlobals(); + $s->handleTokenRequest($request)->send(); killme(); } -- cgit v1.2.3 From 45e0fc6802b360710becf7ddaf6aed6a9de1d876 Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Mon, 26 Feb 2018 18:16:43 -0500 Subject: Successful OAuth2 sequence demonstrated with the test vehicle, including an authenticated API call using an access_token. --- Zotlabs/Module/Authorize.php | 36 ++++-------- Zotlabs/Module/Oauth2testvehicle.php | 106 ++++++++++++++++++++++------------- 2 files changed, 77 insertions(+), 65 deletions(-) (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php index f505b4681..c76dfb9df 100644 --- a/Zotlabs/Module/Authorize.php +++ b/Zotlabs/Module/Authorize.php @@ -6,28 +6,6 @@ use Zotlabs\Identity\OAuth2Storage; class Authorize extends \Zotlabs\Web\Controller { - function init() { - - // workaround for HTTP-auth in CGI mode - if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { - $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); - if (strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - } - - if (x($_SERVER, 'HTTP_AUTHORIZATION')) { - $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)); - if (strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - } - } - function get() { if (!local_channel()) { return login(); @@ -37,7 +15,7 @@ class Authorize extends \Zotlabs\Web\Controller { // http://openid.net/specs/openid-connect-registration-1_0.html $app = array( 'name' => (x($_REQUEST, 'client_name') ? urldecode($_REQUEST['client_name']) : 'Unknown App'), - 'icon' => (x($_REQUEST, 'logo_uri') ? urldecode($_REQUEST['logo_uri']) : '/images/icons/plugin.png'), + 'icon' => (x($_REQUEST, 'logo_uri') ? urldecode($_REQUEST['logo_uri']) : z_root() . '/images/icons/plugin.png'), 'url' => (x($_REQUEST, 'client_uri') ? urldecode($_REQUEST['client_uri']) : ''), ); $o .= replace_macros(get_markup_template('oauth_authorize.tpl'), array( @@ -76,20 +54,26 @@ class Authorize extends \Zotlabs\Web\Controller { if (x($_POST, 'redirect_uri')) { $redirect_uri = $_POST['redirect_uri']; } else { - $redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com'; + $redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com/oauth'; } $request = \OAuth2\Request::createFromGlobals(); $response = new \OAuth2\Response(); // If the client is not registered, add to the database - if (!$storage->getClientDetails($client_id)) { + if (!$client = $storage->getClientDetails($client_id)) { $client_secret = random_string(16); // Client apps are registered per channel $user_id = local_channel(); $storage->setClientDetails($client_id, $client_secret, $redirect_uri, 'authorization_code', null, $user_id); - $response->setParameter('client_secret', $client_secret); + + } + if (!$client = $storage->getClientDetails($client_id)) { + // There was an error registering the client. + $response->send(); + killme(); } + $response->setParameter('client_secret', $client['client_secret']); // validate the authorize request if (!$s->validateAuthorizeRequest($request, $response)) { diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/Oauth2testvehicle.php index 37a0b9b0e..29c6ec50e 100644 --- a/Zotlabs/Module/Oauth2testvehicle.php +++ b/Zotlabs/Module/Oauth2testvehicle.php @@ -2,6 +2,12 @@ namespace Zotlabs\Module; +/** + * The OAuth2TestVehicle class is a way to test the registration of an OAuth2 + * client app. It allows you to walk through the steps of registering a client, + * requesting an authorization code for that client, and then requesting an + * access token for use in authentication against the Hubzilla API endpoints. + */ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { function init() { @@ -14,17 +20,19 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { // cookie, and compare it when the user comes back. This ensures your // redirection endpoint isn't able to be tricked into attempting to // exchange arbitrary authorization codes." - if ($_REQUEST['code'] && $_REQUEST['state']) { - logger('Authorization callback invoked.', LOGGER_DEBUG); - logger(json_encode($_REQUEST, JSON_PRETTY_PRINT), LOGGER_DEBUG); - info('Authorization callback invoked.' . EOL); - return $this->get(); - } + $_SESSION['redirect_uri'] = 'http://hub.localhost/oauth2testvehicle'; + $_SESSION['authorization_code'] = (x($_REQUEST, 'code') ? $_REQUEST['code'] : $_SESSION['authorization_code']); + $_SESSION['state'] = (x($_REQUEST, 'state') ? $_REQUEST['state'] : $_SESSION['state'] ); + $_SESSION['client_id'] = (x($_REQUEST, 'client_id') ? $_REQUEST['client_id'] : $_SESSION['client_id'] ); + $_SESSION['client_secret'] = (x($_REQUEST, 'client_secret') ? $_REQUEST['client_secret'] : $_SESSION['client_secret']); + $_SESSION['access_token'] = (x($_REQUEST, 'access_token') ? $_REQUEST['access_token'] : $_SESSION['access_token'] ); + $_SESSION['api_response'] = (x($_SESSION, 'api_response') ? $_SESSION['api_response'] : ''); } function get() { - + $o .= replace_macros(get_markup_template('oauth2testvehicle.tpl'), array( '$baseurl' => z_root(), + '$api_response' => $_SESSION['api_response'], /* endpoints => array( array( @@ -49,7 +57,8 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { ), 'oauth2test_delete_db', 'Delete the OAuth2 database tables', - 'POST' + 'POST', + ($_SESSION['success'] === 'delete_db'), ), array( 'oauth2testvehicle', @@ -60,58 +69,76 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { ), 'oauth2test_create_db', 'Create the OAuth2 database tables', - 'POST' + 'POST', + ($_SESSION['success'] === 'create_db'), ), array( 'authorize', array( array('response_type', 'code'), - array('client_id', urlencode('killer_app')), - array('redirect_uri', 'http://hub.localhost/oauth2testvehicle'), + array('client_id', (x($_REQUEST, 'client_id') ? $_REQUEST['client_id'] : 'oauth2_test_app')), + array('redirect_uri', $_SESSION['redirect_uri']), array('state', 'xyz'), // OpenID Connect Dynamic Client Registration 1.0 Client Metadata // http://openid.net/specs/openid-connect-registration-1_0.html - array('client_name', urlencode('Killer App')), - array('logo_uri', urlencode('https://client.example.com/website/img/icon.png')), + array('client_name', 'OAuth2 Test App'), + array('logo_uri', urlencode(z_root() . '/images/icons/plugin.png')), array('client_uri', urlencode('https://client.example.com/website')), array('application_type', 'web'), // would be 'native' for mobile app ), 'oauth_authorize', 'Authorize a test client app', - 'GET' + 'GET', + (($_REQUEST['code'] && $_REQUEST['state']) ? true : false), ), - /* - * POST https://api.authorization-server.com/token - grant_type=authorization_code& - code=AUTH_CODE_HERE& - redirect_uri=REDIRECT_URI& - client_id=CLIENT_ID - */ array( 'oauth2testvehicle', array( array('action', 'request_token'), array('grant_type', 'authorization_code'), - array('code', (x($_REQUEST, 'code') ? $_REQUEST['code'] : 'no_authorization_code')), - array('redirect_uri', 'http://hub.localhost/oauth2testvehicle'), - array('client_id', urlencode('killer_app')), - array('client_secret', (x($_REQUEST, 'client_secret') ? $_REQUEST['client_secret'] : 'no_client_secret')), + array('code', $_SESSION['authorization_code']), + array('redirect_uri', $_SESSION['redirect_uri']), + array('client_id', ($_SESSION['client_id'] ? $_SESSION['client_id'] : 'oauth2_test_app')), + array('client_secret', $_SESSION['client_secret']), ), 'oauth_token_request', 'Request a token', - 'POST' + 'POST', + ($_SESSION['success'] === 'request_token'), + ), + array( + 'oauth2testvehicle', + array( + array('action', 'api_files'), + array('access_token', $_SESSION['access_token']), + ), + 'oauth_api_files', + 'API: Get channel files', + 'POST', + ($_SESSION['success'] === 'api_files'), ) ) )); - + $_SESSION['success'] = ''; return $o; } function post() { - //logger(json_encode($_POST, JSON_PRETTY_PRINT), LOGGER_DEBUG); - switch ($_POST['action']) { + case 'api_files': + $access_token = $_SESSION['access_token']; + $url = z_root() . '/api/z/1.0/files/'; + $headers = []; + $headers[] = 'Authorization: Bearer ' . $access_token; + $post = z_fetch_url($url, false, 0, array( + 'custom' => 'GET', + 'headers' => $headers, + )); + logger(json_encode($post, JSON_PRETTY_PRINT), LOGGER_DEBUG); + $response = json_decode($post['body'], true); + $_SESSION['api_response'] = json_encode($response, JSON_PRETTY_PRINT); + break; case 'request_token': $grant_type = (x($_POST, 'grant_type') ? $_POST['grant_type'] : ''); $redirect_uri = (x($_POST, 'redirect_uri') ? $_POST['redirect_uri'] : ''); @@ -119,19 +146,21 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { $code = (x($_POST, 'code') ? $_POST['code'] : ''); $client_secret = (x($_POST, 'client_secret') ? $_POST['client_secret'] : ''); $url = z_root() . '/token/?'; - $url .= 'grant_type=' . urlencode($grant_type); + $url .= 'grant_type=' . $grant_type; $url .= '&redirect_uri=' . urlencode($redirect_uri); - $url .= '&client_id=' . urlencode($client_id); - $url .= '&code=' . urlencode($code); + $url .= '&client_id=' . $client_id; + $url .= '&code=' . $code; $post = z_fetch_url($url, false, 0, array( 'custom' => 'POST', 'http_auth' => $client_id . ':' . $client_secret, )); - //logger(json_encode($post, JSON_PRETTY_PRINT), LOGGER_DEBUG); + logger(json_encode($post, JSON_PRETTY_PRINT), LOGGER_DEBUG); $response = json_decode($post['body'], true); logger(json_encode($response, JSON_PRETTY_PRINT), LOGGER_DEBUG); if($response['access_token']) { info('Access token received: ' . $response['access_token'] . EOL); + $_SESSION['success'] = 'request_token'; + $_SESSION['access_token'] = $response['access_token']; } break; case 'delete_db': @@ -140,26 +169,23 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { // by passing it the database connection $pdo = \DBA::$dba->db; $storage = new \Zotlabs\Storage\ZotOauth2Pdo($pdo); - logger('Deleting existing database tables...', LOGGER_DEBUG); foreach ($storage->getConfig() as $key => $table) { - logger('Deleting table ' . dbesc($table), LOGGER_DEBUG); $r = q("DROP TABLE %s;", dbesc($table)); if (!$r) { - logger('Errors encountered deleting database table ' . $table . '.', LOGGER_DEBUG); $status = false; } } if (!$status) { notice('Errors encountered deleting database tables.' . EOL); + $_SESSION['success'] = ''; } else { info('Database tables deleted successfully.' . EOL); + $_SESSION['success'] = 'delete_db'; } - break; case 'create_db': $status = true; - logger('Creating database tables...', LOGGER_DEBUG); @include('.htconfig.php'); $pdo = \DBA::$dba->db; $storage = new \Zotlabs\Storage\ZotOauth2Pdo($pdo); @@ -168,15 +194,17 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { $result = $pdo->exec($statement); } catch (\PDOException $e) { $status = false; - logger('Error executing database statement: ' . $statement, LOGGER_DEBUG); } } if (!$status) { notice('Errors encountered creating database tables.' . EOL); + $_SESSION['success'] = ''; } else { info('Database tables created successfully.' . EOL); + $_SESSION['success'] = 'create_db'; } + break; default: break; -- cgit v1.2.3 From aa6f7481a023c04b30ffc6aec2016e2b7b3b386f Mon Sep 17 00:00:00 2001 From: Andrew Manning Date: Sat, 10 Mar 2018 15:43:13 -0500 Subject: Fixed access_token request bug and returned oauth2-server-php library to unmodified state. --- Zotlabs/Module/Oauth2testvehicle.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'Zotlabs/Module') diff --git a/Zotlabs/Module/Oauth2testvehicle.php b/Zotlabs/Module/Oauth2testvehicle.php index 29c6ec50e..82e309f1c 100644 --- a/Zotlabs/Module/Oauth2testvehicle.php +++ b/Zotlabs/Module/Oauth2testvehicle.php @@ -145,13 +145,14 @@ class OAuth2TestVehicle extends \Zotlabs\Web\Controller { $client_id = (x($_POST, 'client_id') ? $_POST['client_id'] : ''); $code = (x($_POST, 'code') ? $_POST['code'] : ''); $client_secret = (x($_POST, 'client_secret') ? $_POST['client_secret'] : ''); - $url = z_root() . '/token/?'; - $url .= 'grant_type=' . $grant_type; - $url .= '&redirect_uri=' . urlencode($redirect_uri); - $url .= '&client_id=' . $client_id; - $url .= '&code=' . $code; - $post = z_fetch_url($url, false, 0, array( - 'custom' => 'POST', + $url = z_root() . '/token/'; + $params = http_build_query(array( + 'grant_type' => $grant_type, + 'redirect_uri' => urlencode($redirect_uri), + 'client_id' => $client_id, + 'code' => $code, + )); + $post = z_post_url($url, $params, 0, array( 'http_auth' => $client_id . ':' . $client_secret, )); logger(json_encode($post, JSON_PRETTY_PRINT), LOGGER_DEBUG); -- cgit v1.2.3