From 2d35f382c08a5bf56c2b8641c4f43f2fa20f2cae Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Mon, 21 Sep 2015 16:10:28 -0700 Subject: [PATCH] also support native github login --- compass/app/Http/Controllers/IndieAuth.php | 113 +++++++++-- compass/app/Http/routes.php | 1 + compass/composer.json | 3 +- compass/composer.lock | 222 ++++++++++++++++++++- 4 files changed, 323 insertions(+), 16 deletions(-) diff --git a/compass/app/Http/Controllers/IndieAuth.php b/compass/app/Http/Controllers/IndieAuth.php index 701f845..5ebbb13 100644 --- a/compass/app/Http/Controllers/IndieAuth.php +++ b/compass/app/Http/Controllers/IndieAuth.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers; use Laravel\Lumen\Routing\Controller as BaseController; use Illuminate\Http\Request; +use GuzzleHttp; class IndieAuth extends BaseController { @@ -17,23 +18,36 @@ class IndieAuth extends BaseController return view('auth/error', ['error' => 'Invalid URL']); } - $authorizationEndpoint = \IndieAuth\Client::discoverAuthorizationEndpoint($me); - $tokenEndpoint = \IndieAuth\Client::discoverTokenEndpoint($me); - $state = \IndieAuth\Client::generateStateParameter(); - session([ - 'auth_state' => $state, - 'attempted_me' => $me, - 'authorization_endpoint' => $authorizationEndpoint, - 'token_endpoint' => $tokenEndpoint - ]); - // If the user specified only an authorization endpoint, use that - if(!$authorizationEndpoint) { - // Otherwise, fall back to indieauth.com - $authorizationEndpoint = env('DEFAULT_AUTH_ENDPOINT'); + if(preg_match('/https?:\/\/github\.com\/[^ \/]+/', $me)) { + $authorizationURL = 'https://github.com/login/oauth/authorize' + . '?client_id=' . env('GITHUB_ID') + . '&state=' . $state; + + session([ + 'auth_state' => $state, + 'attempted_me' => $me, + ]); + + } else { + $authorizationEndpoint = \IndieAuth\Client::discoverAuthorizationEndpoint($me); + $tokenEndpoint = \IndieAuth\Client::discoverTokenEndpoint($me); + + session([ + 'auth_state' => $state, + 'attempted_me' => $me, + 'authorization_endpoint' => $authorizationEndpoint, + 'token_endpoint' => $tokenEndpoint + ]); + + // If the user specified only an authorization endpoint, use that + if(!$authorizationEndpoint) { + // Otherwise, fall back to indieauth.com + $authorizationEndpoint = env('DEFAULT_AUTH_ENDPOINT'); + } + $authorizationURL = \IndieAuth\Client::buildAuthorizationURL($authorizationEndpoint, $me, $this->_redirectURI(), env('BASE_URL'), $state); } - $authorizationURL = \IndieAuth\Client::buildAuthorizationURL($authorizationEndpoint, $me, $this->_redirectURI(), env('BASE_URL'), $state); return redirect($authorizationURL); } @@ -73,6 +87,77 @@ class IndieAuth extends BaseController return redirect('/'); } + public function github(Request $request) { + if(!session('auth_state') || !session('attempted_me')) { + return view('auth/error', ['error' => 'Missing state information. Start over.']); + } + + if($request->input('error')) { + return view('auth/error', ['error' => $request->input('error')]); + } + + if(session('auth_state') != $request->input('state')) { + return view('auth/error', ['error' => 'State did not match. Start over.']); + } + + if(!$request->input('code')) { + return view('auth/error', ['error' => 'An unknown error occurred']); + } + + $client = new GuzzleHttp\Client([ + 'http_errors' => false + ]); + $res = $client->post('https://github.com/login/oauth/access_token', [ + 'form_params' => [ + 'client_id' => env('GITHUB_ID'), + 'client_secret' => env('GITHUB_SECRET'), + // 'redirect_uri' => env('BASE_URL') . 'auth/github', + 'code' => $request->input('code'), + 'state' => session('auth_state') + ], + 'headers' => [ + 'Accept' => 'application/json' + ] + ]); + if($res->getStatusCode() == 200) { + $body = $res->getBody(); + $data = json_decode($body); + if($data) { + if(property_exists($data, 'access_token')) { + + // Now check the username of the user that just logged in + $res = $client->get('https://api.github.com/user', [ + 'headers' => [ + 'Authorization' => 'token ' . $data->access_token + ] + ]); + if($res->getStatusCode() == 200) { + $data = json_decode($res->getBody()); + if(property_exists($data, 'login')) { + session()->flush(); + session(['me' => 'https://github.com/' . $data->login]); + return redirect('/'); + } else { + return view('auth/error', ['error' => 'Login failed']); + } + } else { + return view('auth/error', ['error' => 'Login failed']); + } + } else { + $err = ''; + if(property_exists($data, 'error_description')) { + $err = ': ' . $data->error_description; + } + return view('auth/error', ['error' => 'Login failed' . $err]); + } + } else { + return view('auth/error', ['error' => 'Error parsing response body from GitHub']); + } + } else { + return view('auth/error', ['error' => 'Could not verify login from GitHub: ' . $res->getBody()]); + } + } + public function logout(Request $request) { session()->flush(); return redirect('/'); diff --git a/compass/app/Http/routes.php b/compass/app/Http/routes.php index 5fba600..c247693 100644 --- a/compass/app/Http/routes.php +++ b/compass/app/Http/routes.php @@ -17,4 +17,5 @@ $app->get('/', function () use ($app) { $app->post('/auth/start', 'IndieAuth@start'); $app->get('/auth/callback', 'IndieAuth@callback'); +$app->get('/auth/github', 'IndieAuth@github'); $app->get('/auth/logout', 'IndieAuth@logout'); diff --git a/compass/composer.json b/compass/composer.json index f5ce082..bfc7cf1 100644 --- a/compass/composer.json +++ b/compass/composer.json @@ -9,7 +9,8 @@ "laravel/lumen-framework": "5.1.*", "vlucas/phpdotenv": "~1.0", "p3k/quartz-db": "0.1.*", - "indieauth/client": "0.1.*" + "indieauth/client": "0.1.*", + "guzzlehttp/guzzle":"~6.0" }, "require-dev": { "phpunit/phpunit": "~4.0", diff --git a/compass/composer.lock b/compass/composer.lock index 0224367..db6fc8d 100644 --- a/compass/composer.lock +++ b/compass/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "8a5149b30d42771977b782ff51b215ee", + "hash": "5a5fae61e7139c98dd26b3cadb4fcbce", "packages": [ { "name": "barnabywalters/mf-cleaner", @@ -169,6 +169,177 @@ ], "time": "2014-12-20 21:24:13" }, + { + "name": "guzzlehttp/guzzle", + "version": "6.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd14b4d0b8f2389eaf37c5458608c7cb793a81", + "reference": "66fd14b4d0b8f2389eaf37c5458608c7cb793a81", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.5.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.1-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2015-09-08 17:36:26" + }, + { + "name": "guzzlehttp/promises", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "97fe7210def29451ec74923b27e552238defd75a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/97fe7210def29451ec74923b27e552238defd75a", + "reference": "97fe7210def29451ec74923b27e552238defd75a", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2015-08-15 19:37:21" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/4ef919b0cf3b1989523138b60163bbcb7ba1ff7e", + "reference": "4ef919b0cf3b1989523138b60163bbcb7ba1ff7e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2015-08-15 19:32:36" + }, { "name": "illuminate/auth", "version": "v5.1.16", @@ -1734,6 +1905,55 @@ "description": "A flat-file database optimized to hold time-series data.", "time": "2015-09-21 17:56:12" }, + { + "name": "psr/http-message", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2015-05-04 20:22:00" + }, { "name": "psr/log", "version": "1.0.0",