From 3d4c38c7ee272f8f101857d58d2ad0d25db50fe3 Mon Sep 17 00:00:00 2001 From: James Brooks Date: Sat, 3 Jan 2015 17:51:35 +0000 Subject: [PATCH] User-based API key. Closes #256. --- app/config/app.php | 3 +- app/config/packages/dingo/api/config.php | 6 +++ ..._01_03_120438_AlterTableUsersAddApiKey.php | 32 +++++++++++++ app/routes/dashboard.php | 1 + app/views/dashboard/user/index.blade.php | 7 +++ src/Auth/ApiKeyAuthenticator.php | 48 +++++++++++++++++++ src/Http/Controllers/DashUserController.php | 14 ++++++ src/Models/User.php | 46 ++++++++++++++++++ src/Providers/AuthServiceProvider.php | 31 ++++++++++++ 9 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php create mode 100644 src/Auth/ApiKeyAuthenticator.php create mode 100644 src/Providers/AuthServiceProvider.php diff --git a/app/config/app.php b/app/config/app.php index bffe61b3..1f294f4f 100644 --- a/app/config/app.php +++ b/app/config/app.php @@ -128,9 +128,10 @@ return [ 'Roumen\Feed\FeedServiceProvider', 'Thujohn\Rss\RssServiceProvider', + 'CachetHQ\Cachet\Providers\AuthServiceProvider', + 'CachetHQ\Cachet\Providers\ConsoleServiceProvider', 'CachetHQ\Cachet\Providers\RepositoryServiceProvider', 'CachetHQ\Cachet\Providers\RoutingServiceProvider', - 'CachetHQ\Cachet\Providers\ConsoleServiceProvider', ], diff --git a/app/config/packages/dingo/api/config.php b/app/config/packages/dingo/api/config.php index 440c5aff..5c1e2965 100644 --- a/app/config/packages/dingo/api/config.php +++ b/app/config/packages/dingo/api/config.php @@ -76,9 +76,15 @@ return [ */ 'auth' => [ + 'basic' => function ($app) { return new Dingo\Api\Auth\BasicProvider($app['auth']); }, + + 'api_key' => function ($app) { + return new CachetHQ\Cachet\Auth\ApiKeyAuthenticator(); + }, + ], /* diff --git a/app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php b/app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php new file mode 100644 index 00000000..4735512b --- /dev/null +++ b/app/database/migrations/2015_01_03_120438_AlterTableUsersAddApiKey.php @@ -0,0 +1,32 @@ +string('api_key')->after('email'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn(); + }); + } +} diff --git a/app/routes/dashboard.php b/app/routes/dashboard.php index 2adb886e..2974c015 100644 --- a/app/routes/dashboard.php +++ b/app/routes/dashboard.php @@ -37,6 +37,7 @@ Route::group(['before' => 'auth', 'prefix' => 'dashboard', 'namespace' => 'Cache // User Settings Route::get('user', ['as' => 'dashboard.user', 'uses' => 'DashUserController@showUser']); + Route::get('/user/{user}/api/regen', 'DashUserController@regenerateApiKey'); Route::post('user', 'DashUserController@postUser'); // Internal API. diff --git a/app/views/dashboard/user/index.blade.php b/app/views/dashboard/user/index.blade.php index 87101e5b..80794231 100644 --- a/app/views/dashboard/user/index.blade.php +++ b/app/views/dashboard/user/index.blade.php @@ -33,9 +33,16 @@ +
+
+ + + Regenerating your API key will revoke all existing applications. +
+ Regenerate API Key diff --git a/src/Auth/ApiKeyAuthenticator.php b/src/Auth/ApiKeyAuthenticator.php new file mode 100644 index 00000000..64cd9711 --- /dev/null +++ b/src/Auth/ApiKeyAuthenticator.php @@ -0,0 +1,48 @@ +input('api_key', false); + + if ($api_key === false) { + throw new UnauthorizedHttpException(null, 'You did not provide an API key.'); + } + + try { + return User::findByApiKey($api_key); + } catch (ModelNotFoundException $e) { + throw new UnauthorizedHttpException(null, 'The API key you provided was not correct.'); + } + } + + /** + * Get the providers authorization method. + * + * @return string + */ + public function getAuthorizationMethod() + { + return 'api_key'; + } +} diff --git a/src/Http/Controllers/DashUserController.php b/src/Http/Controllers/DashUserController.php index fcdca258..d664e296 100644 --- a/src/Http/Controllers/DashUserController.php +++ b/src/Http/Controllers/DashUserController.php @@ -2,6 +2,7 @@ namespace CachetHQ\Cachet\Http\Controllers; +use CachetHQ\Cachet\Models\User; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Auth; @@ -35,4 +36,17 @@ class DashUserController extends Controller return Redirect::back()->with('updated', $updated); } + + /** + * Regenerates the users API key. + * + * @return \Illuminate\View\View + */ + public function regenerateApiKey(User $user) + { + $user->api_key = User::generateApiKey(); + $user->save(); + + return Redirect::back(); + } } diff --git a/src/Models/User.php b/src/Models/User.php index c48afad3..2d122f61 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -7,6 +7,7 @@ use Illuminate\Auth\Reminders\RemindableTrait; use Illuminate\Auth\UserInterface; use Illuminate\Auth\UserTrait; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Support\Facades\Hash; /** @@ -47,6 +48,20 @@ class User extends Model implements UserInterface, RemindableInterface */ protected $guarded = []; + /** + * Overrides the models boot method. + * + * @return void + */ + public static function boot() + { + parent::boot(); + + self::creating(function ($user) { + $user->api_key = self::generateApiKey(); + }); + } + /** * Hash any password being inserted by default. * @@ -72,4 +87,35 @@ class User extends Model implements UserInterface, RemindableInterface { return sprintf('https://www.gravatar.com/avatar/%s?size=%d', md5($this->email), $size); } + + /** + * Find by api_key, or throw an exception. + * + * @param string $api_key + * @param string[] $columns + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @return \CachetHQ\Cachet\Models\User + */ + public static function findByApiKey($api_key, $columns = ['*']) + { + $user = static::where('api_key', $api_key)->first($columns); + + if (!$user) { + throw new ModelNotFoundException(); + } + + return $user; + } + + /** + * Returns an API key. + * + * @return string + */ + public static function generateApiKey() + { + return str_random(20); + } } diff --git a/src/Providers/AuthServiceProvider.php b/src/Providers/AuthServiceProvider.php new file mode 100644 index 00000000..babf42a0 --- /dev/null +++ b/src/Providers/AuthServiceProvider.php @@ -0,0 +1,31 @@ +app->bindShared('CachetHQ\Cachet\Auth\ApiKeyAuthenticator', function () { + return new ApiKeyAuthenticator(); + }); + } +}