Page MenuHomePhorge

D2494.1775285285.diff
No OneTemporary

Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None

D2494.1775285285.diff

diff --git a/bin/quickstart.sh b/bin/quickstart.sh
--- a/bin/quickstart.sh
+++ b/bin/quickstart.sh
@@ -66,10 +66,11 @@
npm install
find bootstrap/cache/ -type f ! -name ".gitignore" -delete
./artisan key:generate
-./artisan jwt:secret -f
./artisan clear-compiled
./artisan cache:clear
./artisan horizon:install
+./artisan passport:keys --force
+
if [ ! -z "$(rpm -qv chromium 2>/dev/null)" ]; then
chver=$(rpmquery --queryformat="%{VERSION}" chromium | awk -F'.' '{print $1}')
diff --git a/src/.env.example b/src/.env.example
--- a/src/.env.example
+++ b/src/.env.example
@@ -128,8 +128,8 @@
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
-JWT_SECRET=
-JWT_TTL=60
+PROXY_OAUTH_CLIENT_ID=1
+PROXY_OAUTH_CLIENT_SECRET=JF4pL68ucLuMupaOviTeG8EJeQpjtZtcGLp4f0dq
COMPANY_NAME=
COMPANY_ADDRESS=
diff --git a/src/app/Http/Controllers/API/AuthController.php b/src/app/Http/Controllers/API/AuthController.php
--- a/src/app/Http/Controllers/API/AuthController.php
+++ b/src/app/Http/Controllers/API/AuthController.php
@@ -7,6 +7,8 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
+use Laravel\Passport\TokenRepository;
+use Laravel\Passport\RefreshTokenRepository;
class AuthController extends Controller
{
@@ -20,9 +22,8 @@
$user = Auth::guard()->user();
$response = V4\UsersController::userResponse($user);
- if (!empty(request()->input('refresh_token'))) {
- // @phpstan-ignore-next-line
- return $this->respondWithToken(Auth::guard()->refresh(), $response);
+ if (!empty(request()->input('refresh'))) {
+ return $this->refreshAndRespond(request(), $response);
}
return response()->json($response);
@@ -36,12 +37,21 @@
*/
public static function logonResponse(User $user)
{
- // @phpstan-ignore-next-line
- $token = Auth::guard()->login($user);
+ $proxyRequest = Request::create('/oauth/token', 'POST', [
+ 'username' => $user->email,
+ 'password' => $user->password,
+ 'grant_type' => 'password',
+ 'client_id' => config('auth.proxy.client_id'),
+ 'client_secret' => config('auth.proxy.client_secret'),
+ 'scopes' => '[*]'
+ ]);
+
+ $tokenResponse = app()->handle($proxyRequest);
+
$response = V4\UsersController::userResponse($user);
$response['status'] = 'success';
- return self::respondWithToken($token, $response);
+ return self::respondWithToken($tokenResponse, $response);
}
/**
@@ -66,19 +76,33 @@
return response()->json(['status' => 'error', 'errors' => $v->errors()], 422);
}
- $credentials = $request->only('email', 'password');
+ $proxyRequest = Request::create('/oauth/token', 'POST', [
+ 'username' => $request->email,
+ 'password' => $request->password,
+ 'grant_type' => 'password',
+ 'client_id' => config('auth.proxy.client_id'),
+ 'client_secret' => config('auth.proxy.client_secret'),
+ 'scopes' => '[*]'
+ ]);
+
+ $tokenResponse = app()->handle($proxyRequest);
+
+ if ($tokenResponse->getStatusCode() === 200) {
+ $user = \App\User::where('email', $request->email)->first();
+ if (!$user) {
+ throw new \Exception("Authentication required.");
+ }
- if ($token = Auth::guard()->attempt($credentials)) {
- $user = Auth::guard()->user();
$sf = new \App\Auth\SecondFactor($user);
+ // Returns null on success
if ($response = $sf->requestHandler($request)) {
return $response;
}
$response = V4\UsersController::userResponse($user);
- return $this->respondWithToken($token, $response);
+ return $this->respondWithToken($tokenResponse, $response);
}
return response()->json(['status' => 'error', 'message' => __('auth.failed')], 401);
@@ -91,8 +115,16 @@
*/
public function logout()
{
- Auth::guard()->logout();
+ $tokenId = Auth::user()->token()->id;
+
+ $tokenRepository = app(TokenRepository::class);
+ $refreshTokenRepository = app(RefreshTokenRepository::class);
+
+ // Revoke an access token...
+ $tokenRepository->revokeAccessToken($tokenId);
+ // Revoke all of the token's refresh tokens...
+ $refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);
return response()->json([
'status' => 'success',
'message' => __('auth.logoutsuccess')
@@ -104,26 +136,42 @@
*
* @return \Illuminate\Http\JsonResponse
*/
- public function refresh()
+ public function refresh(Request $request)
{
- // @phpstan-ignore-next-line
- return $this->respondWithToken(Auth::guard()->refresh());
+ return self::refreshAndRespond($request);
+ }
+
+
+ protected static function refreshAndRespond($request, array $response = [])
+ {
+ $proxyRequest = Request::create('/oauth/token', 'POST', [
+ 'grant_type' => 'refresh_token',
+ 'refresh_token' => $request->refresh_token,
+ 'client_id' => config('auth.proxy.client_id'),
+ 'client_secret' => config('auth.proxy.client_secret'),
+ ]);
+
+ $tokenResponse = app()->handle($proxyRequest);
+
+ return self::respondWithToken($tokenResponse, $response);
}
/**
* Get the token array structure.
*
- * @param string $token Respond with this token.
- * @param array $response Additional response data
+ * @param \Illuminate\Http\JsonResponse $tokenResponse The response containing the token.
+ * @param array $response Additional response data
*
* @return \Illuminate\Http\JsonResponse
*/
- protected static function respondWithToken($token, array $response = [])
+ protected static function respondWithToken($tokenResponse, array $response = [])
{
- $response['access_token'] = $token;
+ $data = json_decode($tokenResponse->getContent());
+
+ $response['access_token'] = $data->access_token;
+ $response['refresh_token'] = $data->refresh_token;
$response['token_type'] = 'bearer';
- // @phpstan-ignore-next-line
- $response['expires_in'] = Auth::guard()->factory()->getTTL() * 60;
+ $response['expires_in'] = $data->expires_in;
return response()->json($response);
}
diff --git a/src/app/Providers/AppServiceProvider.php b/src/app/Providers/AppServiceProvider.php
--- a/src/app/Providers/AppServiceProvider.php
+++ b/src/app/Providers/AppServiceProvider.php
@@ -6,6 +6,7 @@
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
+use Laravel\Passport\Passport;
class AppServiceProvider extends ServiceProvider
{
@@ -16,7 +17,7 @@
*/
public function register()
{
- //
+ Passport::ignoreMigrations();
}
/**
diff --git a/src/app/Providers/AuthServiceProvider.php b/src/app/Providers/AuthServiceProvider.php
--- a/src/app/Providers/AuthServiceProvider.php
+++ b/src/app/Providers/AuthServiceProvider.php
@@ -6,6 +6,7 @@
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
+use Laravel\Passport\Passport;
class AuthServiceProvider extends ServiceProvider
{
@@ -33,5 +34,11 @@
return new LDAPUserProvider($app['hash'], $config['model']);
}
);
+ //Hashes all secrets and thus makes them non-recoverable
+ /* Passport::hashClientSecrets(); */
+ Passport::routes();
+ Passport::tokensExpireIn(now()->addMinutes(\config('auth.token_expiry_minutes')));
+ Passport::refreshTokensExpireIn(now()->addMinutes(\config('auth.refresh_token_expiry_minutes')));
+ Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}
}
diff --git a/src/app/User.php b/src/app/User.php
--- a/src/app/User.php
+++ b/src/app/User.php
@@ -11,7 +11,7 @@
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Iatstuti\Database\Support\NullableFields;
-use Tymon\JWTAuth\Contracts\JWTSubject;
+use Laravel\Passport\HasApiTokens;
/**
* The eloquent definition of a User.
@@ -21,12 +21,13 @@
* @property string $password
* @property int $status
*/
-class User extends Authenticatable implements JWTSubject
+class User extends Authenticatable
{
use NullableFields;
use UserAliasesTrait;
use SettingsTrait;
use SoftDeletes;
+ use HasApiTokens;
// a new user, default on creation
public const STATUS_NEW = 1 << 0;
@@ -401,15 +402,7 @@
return null;
}
- public function getJWTIdentifier()
- {
- return $this->getKey();
- }
- public function getJWTCustomClaims()
- {
- return [];
- }
/**
* Return groups controlled by the current user.
diff --git a/src/composer.json b/src/composer.json
--- a/src/composer.json
+++ b/src/composer.json
@@ -22,6 +22,7 @@
"kolab/net_ldap3": "dev-master",
"laravel/framework": "6.*",
"laravel/horizon": "^3",
+ "laravel/passport": "^9",
"laravel/tinker": "^2.4",
"mollie/laravel-mollie": "^2.9",
"morrislaptop/laravel-queue-clear": "^1.2",
@@ -29,8 +30,7 @@
"spatie/laravel-translatable": "^4.2",
"spomky-labs/otphp": "~4.0.0",
"stripe/stripe-php": "^7.29",
- "swooletw/laravel-swoole": "^2.6",
- "tymon/jwt-auth": "^1.0"
+ "swooletw/laravel-swoole": "^2.6"
},
"require-dev": {
"beyondcode/laravel-dump-server": "^1.0",
diff --git a/src/config/app.php b/src/config/app.php
--- a/src/config/app.php
+++ b/src/config/app.php
@@ -183,6 +183,7 @@
* Package Service Providers...
*/
Barryvdh\DomPDF\ServiceProvider::class,
+ Laravel\Passport\PassportServiceProvider::class,
/*
* Application Service Providers...
diff --git a/src/config/auth.php b/src/config/auth.php
--- a/src/config/auth.php
+++ b/src/config/auth.php
@@ -42,7 +42,7 @@
],
'api' => [
- 'driver' => 'jwt',
+ 'driver' => 'passport',
'provider' => 'users',
],
],
@@ -99,4 +99,25 @@
],
],
+
+ /*
+ |--------------------------------------------------------------------------
+ | OAuth Proxy Authentication
+ |--------------------------------------------------------------------------
+ |
+ | If you are planning to use your application to self-authenticate as a
+ | proxy, you can define the client and grant type to use here. This is
+ | sometimes the case when a trusted Single Page Application doesn't
+ | use a backend to send the authentication request, but instead
+ | relies on the API to handle proxying the request to itself.
+ |
+ */
+
+ 'proxy' => [
+ 'client_id' => env('PROXY_OAUTH_CLIENT_ID'),
+ 'client_secret' => env('PROXY_OAUTH_CLIENT_SECRET'),
+ ],
+
+ 'token_expiry_minutes' => 1 * 24 * 60,
+ 'refresh_token_expiry_minutes' => 30 * 24 * 60,
];
diff --git a/src/config/jwt.php b/src/config/jwt.php
deleted file mode 100644
--- a/src/config/jwt.php
+++ /dev/null
@@ -1,304 +0,0 @@
-<?php
-
-/*
- * This file is part of jwt-auth.
- *
- * (c) Sean Tymon <tymon148@gmail.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-return [
-
- /*
- |--------------------------------------------------------------------------
- | JWT Authentication Secret
- |--------------------------------------------------------------------------
- |
- | Don't forget to set this in your .env file, as it will be used to sign
- | your tokens. A helper command is provided for this:
- | `php artisan jwt:secret`
- |
- | Note: This will be used for Symmetric algorithms only (HMAC),
- | since RSA and ECDSA use a private/public key combo (See below).
- |
- */
-
- 'secret' => env('JWT_SECRET'),
-
- /*
- |--------------------------------------------------------------------------
- | JWT Authentication Keys
- |--------------------------------------------------------------------------
- |
- | The algorithm you are using, will determine whether your tokens are
- | signed with a random string (defined in `JWT_SECRET`) or using the
- | following public & private keys.
- |
- | Symmetric Algorithms:
- | HS256, HS384 & HS512 will use `JWT_SECRET`.
- |
- | Asymmetric Algorithms:
- | RS256, RS384 & RS512 / ES256, ES384 & ES512 will use the keys below.
- |
- */
-
- 'keys' => [
-
- /*
- |--------------------------------------------------------------------------
- | Public Key
- |--------------------------------------------------------------------------
- |
- | A path or resource to your public key.
- |
- | E.g. 'file://path/to/public/key'
- |
- */
-
- 'public' => env('JWT_PUBLIC_KEY'),
-
- /*
- |--------------------------------------------------------------------------
- | Private Key
- |--------------------------------------------------------------------------
- |
- | A path or resource to your private key.
- |
- | E.g. 'file://path/to/private/key'
- |
- */
-
- 'private' => env('JWT_PRIVATE_KEY'),
-
- /*
- |--------------------------------------------------------------------------
- | Passphrase
- |--------------------------------------------------------------------------
- |
- | The passphrase for your private key. Can be null if none set.
- |
- */
-
- 'passphrase' => env('JWT_PASSPHRASE'),
-
- ],
-
- /*
- |--------------------------------------------------------------------------
- | JWT time to live
- |--------------------------------------------------------------------------
- |
- | Specify the length of time (in minutes) that the token will be valid for.
- | Defaults to 1 hour.
- |
- | You can also set this to null, to yield a never expiring token.
- | Some people may want this behaviour for e.g. a mobile app.
- | This is not particularly recommended, so make sure you have appropriate
- | systems in place to revoke the token if necessary.
- | Notice: If you set this to null you should remove 'exp' element from 'required_claims' list.
- |
- */
-
- 'ttl' => env('JWT_TTL', 60),
-
- /*
- |--------------------------------------------------------------------------
- | Refresh time to live
- |--------------------------------------------------------------------------
- |
- | Specify the length of time (in minutes) that the token can be refreshed
- | within. I.E. The user can refresh their token within a 2 week window of
- | the original token being created until they must re-authenticate.
- | Defaults to 2 weeks.
- |
- | You can also set this to null, to yield an infinite refresh time.
- | Some may want this instead of never expiring tokens for e.g. a mobile app.
- | This is not particularly recommended, so make sure you have appropriate
- | systems in place to revoke the token if necessary.
- |
- */
-
- 'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
-
- /*
- |--------------------------------------------------------------------------
- | JWT hashing algorithm
- |--------------------------------------------------------------------------
- |
- | Specify the hashing algorithm that will be used to sign the token.
- |
- | See here: https://github.com/namshi/jose/tree/master/src/Namshi/JOSE/Signer/OpenSSL
- | for possible values.
- |
- */
-
- 'algo' => env('JWT_ALGO', 'HS256'),
-
- /*
- |--------------------------------------------------------------------------
- | Required Claims
- |--------------------------------------------------------------------------
- |
- | Specify the required claims that must exist in any token.
- | A TokenInvalidException will be thrown if any of these claims are not
- | present in the payload.
- |
- */
-
- 'required_claims' => [
- 'iss',
- 'iat',
- 'exp',
- 'nbf',
- 'sub',
- 'jti',
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Persistent Claims
- |--------------------------------------------------------------------------
- |
- | Specify the claim keys to be persisted when refreshing a token.
- | `sub` and `iat` will automatically be persisted, in
- | addition to the these claims.
- |
- | Note: If a claim does not exist then it will be ignored.
- |
- */
-
- 'persistent_claims' => [
- // 'foo',
- // 'bar',
- ],
-
- /*
- |--------------------------------------------------------------------------
- | Lock Subject
- |--------------------------------------------------------------------------
- |
- | This will determine whether a `prv` claim is automatically added to
- | the token. The purpose of this is to ensure that if you have multiple
- | authentication models e.g. `App\User` & `App\OtherPerson`, then we
- | should prevent one authentication request from impersonating another,
- | if 2 tokens happen to have the same id across the 2 different models.
- |
- | Under specific circumstances, you may want to disable this behaviour
- | e.g. if you only have one authentication model, then you would save
- | a little on token size.
- |
- */
-
- 'lock_subject' => true,
-
- /*
- |--------------------------------------------------------------------------
- | Leeway
- |--------------------------------------------------------------------------
- |
- | This property gives the jwt timestamp claims some "leeway".
- | Meaning that if you have any unavoidable slight clock skew on
- | any of your servers then this will afford you some level of cushioning.
- |
- | This applies to the claims `iat`, `nbf` and `exp`.
- |
- | Specify in seconds - only if you know you need it.
- |
- */
-
- 'leeway' => env('JWT_LEEWAY', 0),
-
- /*
- |--------------------------------------------------------------------------
- | Blacklist Enabled
- |--------------------------------------------------------------------------
- |
- | In order to invalidate tokens, you must have the blacklist enabled.
- | If you do not want or need this functionality, then set this to false.
- |
- */
-
- 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true),
-
- /*
- | -------------------------------------------------------------------------
- | Blacklist Grace Period
- | -------------------------------------------------------------------------
- |
- | When multiple concurrent requests are made with the same JWT,
- | it is possible that some of them fail, due to token regeneration
- | on every request.
- |
- | Set grace period in seconds to prevent parallel request failure.
- |
- */
-
- 'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 0),
-
- /*
- |--------------------------------------------------------------------------
- | Cookies encryption
- |--------------------------------------------------------------------------
- |
- | By default Laravel encrypt cookies for security reason.
- | If you decide to not decrypt cookies, you will have to configure Laravel
- | to not encrypt your cookie token by adding its name into the $except
- | array available in the middleware "EncryptCookies" provided by Laravel.
- | see https://laravel.com/docs/master/responses#cookies-and-encryption
- | for details.
- |
- | Set it to true if you want to decrypt cookies.
- |
- */
-
- 'decrypt_cookies' => false,
-
- /*
- |--------------------------------------------------------------------------
- | Providers
- |--------------------------------------------------------------------------
- |
- | Specify the various providers used throughout the package.
- |
- */
-
- 'providers' => [
-
- /*
- |--------------------------------------------------------------------------
- | JWT Provider
- |--------------------------------------------------------------------------
- |
- | Specify the provider that is used to create and decode the tokens.
- |
- */
-
- 'jwt' => Tymon\JWTAuth\Providers\JWT\Lcobucci::class,
-
- /*
- |--------------------------------------------------------------------------
- | Authentication Provider
- |--------------------------------------------------------------------------
- |
- | Specify the provider that is used to authenticate users.
- |
- */
-
- 'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
-
- /*
- |--------------------------------------------------------------------------
- | Storage Provider
- |--------------------------------------------------------------------------
- |
- | Specify the provider that is used to store tokens in the blacklist.
- |
- */
-
- 'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,
-
- ],
-
-];
diff --git a/src/config/swoole_http.php b/src/config/swoole_http.php
--- a/src/config/swoole_http.php
+++ b/src/config/swoole_http.php
@@ -101,7 +101,9 @@
'providers' => [
Illuminate\Pagination\PaginationServiceProvider::class,
App\Providers\AuthServiceProvider::class,
- Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
+ //Without this passport will sort of work,
+ //but PassportServiceProvider will not contain a valid app instance.
+ Laravel\Passport\PassportServiceProvider::class,
],
/*
diff --git a/src/database/migrations/2021_04_28_090011_create_oauth_tables.php b/src/database/migrations/2021_04_28_090011_create_oauth_tables.php
new file mode 100644
--- /dev/null
+++ b/src/database/migrations/2021_04_28_090011_create_oauth_tables.php
@@ -0,0 +1,92 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+// phpcs:ignore
+class CreateOauthTables extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::create('oauth_clients', function (Blueprint $table) {
+ $table->bigIncrements('id');
+ $table->bigInteger('user_id')->nullable()->index();
+ $table->string('name');
+ $table->string('secret', 100)->nullable();
+ $table->string('provider')->nullable();
+ $table->text('redirect');
+ $table->boolean('personal_access_client');
+ $table->boolean('password_client');
+ $table->boolean('revoked');
+ $table->timestamps();
+
+ $table->foreign('user_id')
+ ->references('id')->on('users')
+ ->onDelete('cascade')
+ ->onUpdate('cascade');
+ });
+
+ Schema::create('oauth_personal_access_clients', function (Blueprint $table) {
+ $table->bigIncrements('id');
+ $table->bigInteger('client_id');
+ $table->timestamps();
+ });
+
+ Schema::create('oauth_auth_codes', function (Blueprint $table) {
+ $table->string('id', 100)->primary();
+ $table->bigInteger('user_id')->index();
+ $table->bigInteger('client_id');
+ $table->text('scopes')->nullable();
+ $table->boolean('revoked');
+ $table->dateTime('expires_at')->nullable();
+
+ $table->foreign('user_id')
+ ->references('id')->on('users')
+ ->onDelete('cascade')
+ ->onUpdate('cascade');
+ });
+
+ Schema::create('oauth_access_tokens', function (Blueprint $table) {
+ $table->string('id', 100)->primary();
+ $table->bigInteger('user_id')->nullable()->index();
+ $table->bigInteger('client_id');
+ $table->string('name')->nullable();
+ $table->text('scopes')->nullable();
+ $table->boolean('revoked');
+ $table->timestamps();
+ $table->dateTime('expires_at')->nullable();
+
+ $table->foreign('user_id')
+ ->references('id')->on('users')
+ ->onDelete('cascade')
+ ->onUpdate('cascade');
+ });
+
+ Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
+ $table->string('id', 100)->primary();
+ $table->string('access_token_id', 100)->index();
+ $table->boolean('revoked');
+ $table->dateTime('expires_at')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('oauth_auth_codes');
+ Schema::dropIfExists('oauth_refresh_tokens');
+ Schema::dropIfExists('oauth_access_tokens');
+ Schema::dropIfExists('oauth_personal_access_clients');
+ Schema::dropIfExists('oauth_clients');
+ }
+}
diff --git a/src/database/seeds/DatabaseSeeder.php b/src/database/seeds/DatabaseSeeder.php
--- a/src/database/seeds/DatabaseSeeder.php
+++ b/src/database/seeds/DatabaseSeeder.php
@@ -21,6 +21,7 @@
'PlanSeeder',
'UserSeeder',
'OpenViduRoomSeeder',
+ 'OauthClientSeeder',
];
$env = ucfirst(App::environment());
diff --git a/src/database/seeds/local/OauthClientSeeder.php b/src/database/seeds/local/OauthClientSeeder.php
new file mode 100644
--- /dev/null
+++ b/src/database/seeds/local/OauthClientSeeder.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Database\Seeds\Local;
+
+use Laravel\Passport\Passport;
+use Illuminate\Database\Seeder;
+
+class OauthClientSeeder extends Seeder
+{
+ /**
+ * Run the database seeds.
+ *
+ * This emulates './artisan passport:client --password --name="Kolab Password Grant Client" --provider=users'
+ *
+ * @return void
+ */
+ public function run()
+ {
+ $client = Passport::client()->forceFill([
+ 'user_id' => null,
+ 'name' => "Kolab Password Grant Client",
+ 'secret' => 'JF4pL68ucLuMupaOviTeG8EJeQpjtZtcGLp4f0dq',
+ 'provider' => 'users',
+ 'redirect' => 'http://localhost',
+ 'personal_access_client' => 0,
+ 'password_client' => 1,
+ 'revoked' => false,
+ ]);
+
+ $client->save();
+ }
+}
diff --git a/src/resources/js/app.js b/src/resources/js/app.js
--- a/src/resources/js/app.js
+++ b/src/resources/js/app.js
@@ -137,6 +137,7 @@
}
localStorage.setItem('token', response.access_token)
+ localStorage.setItem('refreshToken', response.refresh_token)
axios.defaults.headers.common.Authorization = 'Bearer ' + response.access_token
if (response.email) {
@@ -171,6 +172,7 @@
logoutUser(redirect) {
store.commit('logoutUser')
localStorage.setItem('token', '')
+ localStorage.setItem('refreshToken', '')
delete axios.defaults.headers.common.Authorization
if (redirect !== false) {
diff --git a/src/resources/vue/App.vue b/src/resources/vue/App.vue
--- a/src/resources/vue/App.vue
+++ b/src/resources/vue/App.vue
@@ -24,7 +24,7 @@
this.$root.startLoading()
axios.defaults.headers.common.Authorization = 'Bearer ' + token
- axios.get('/api/auth/info?refresh_token=1')
+ axios.post('/api/auth/info?refresh=1', {refresh_token: localStorage.getItem("refreshToken")})
.then(response => {
this.$root.loginUser(response.data, false)
this.$root.stopLoading()
diff --git a/src/routes/api.php b/src/routes/api.php
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -27,6 +27,7 @@
['middleware' => 'auth:api'],
function ($router) {
Route::get('info', 'API\AuthController@info');
+ Route::post('info', 'API\AuthController@info');
Route::post('logout', 'API\AuthController@logout');
Route::post('refresh', 'API\AuthController@refresh');
}
diff --git a/src/tests/Feature/Controller/AuthTest.php b/src/tests/Feature/Controller/AuthTest.php
--- a/src/tests/Feature/Controller/AuthTest.php
+++ b/src/tests/Feature/Controller/AuthTest.php
@@ -8,6 +8,27 @@
class AuthTest extends TestCase
{
+
+ /**
+ * Reset all authentication guards to clear any cache users
+ */
+ protected function resetAuth()
+ {
+ $guards = array_keys(config('auth.guards'));
+
+ foreach ($guards as $guard) {
+ $guard = $this->app['auth']->guard($guard);
+
+ if ($guard instanceof \Illuminate\Auth\SessionGuard) {
+ $guard->logout();
+ }
+ }
+
+ $protectedProperty = new \ReflectionProperty($this->app['auth'], 'guards');
+ $protectedProperty->setAccessible(true);
+ $protectedProperty->setValue($this->app['auth'], []);
+ }
+
/**
* {@inheritDoc}
*/
@@ -57,12 +78,13 @@
// Note: Details of the content are tested in testUserResponse()
// Test token refresh via the info request
- // First we log in as we need the token (actingAs() will not work)
+ // First we log in to get the refresh token
$post = ['email' => 'john@kolab.org', 'password' => 'simple123'];
+ $user = $this->getTestUser('john@kolab.org');
$response = $this->post("api/auth/login", $post);
$json = $response->json();
- $response = $this->withHeaders(['Authorization' => 'Bearer ' . $json['access_token']])
- ->get("api/auth/info?refresh_token=1");
+ $response = $this->actingAs($user)
+ ->post("api/auth/info?refresh=1", ['refresh_token' => $json['refresh_token']]);
$response->assertStatus(200);
$json = $response->json();
@@ -108,7 +130,7 @@
$response->assertStatus(200);
$this->assertTrue(!empty($json['access_token']));
- $this->assertEquals(\config('jwt.ttl') * 60, $json['expires_in']);
+ $this->assertEquals(\config('auth.token_expiry_minutes') * 60, $json['expires_in']);
$this->assertEquals('bearer', $json['token_type']);
$this->assertEquals($user->id, $json['id']);
$this->assertEquals($user->email, $json['email']);
@@ -123,7 +145,7 @@
$response->assertStatus(200);
$this->assertTrue(!empty($json['access_token']));
- $this->assertEquals(\config('jwt.ttl') * 60, $json['expires_in']);
+ $this->assertEquals(\config('auth.token_expiry_minutes') * 60, $json['expires_in']);
$this->assertEquals('bearer', $json['token_type']);
// TODO: We have browser tests for 2FA but we should probably also test it here
@@ -146,6 +168,10 @@
$response = $this->json('POST', "api/auth/logout", []);
$response->assertStatus(401);
+ // Request with invalid token
+ $response = $this->withHeaders(['Authorization' => 'Bearer ' . "foobar"])->post("api/auth/logout");
+ $response->assertStatus(401);
+
// Request with valid token
$response = $this->withHeaders(['Authorization' => 'Bearer ' . $token])->post("api/auth/logout");
$response->assertStatus(200);
@@ -154,6 +180,7 @@
$this->assertEquals('success', $json['status']);
$this->assertEquals('Successfully logged out.', $json['message']);
+ $this->resetAuth();
// Check if it really destroyed the token?
$response = $this->withHeaders(['Authorization' => 'Bearer ' . $token])->get("api/auth/info");
@@ -180,15 +207,17 @@
$json = $response->json();
$token = $json['access_token'];
+ $user = $this->getTestUser('john@kolab.org');
+
// Request with a valid token
- $response = $this->withHeaders(['Authorization' => 'Bearer ' . $token])->post("api/auth/refresh");
+ $response = $this->actingAs($user)->post("api/auth/refresh", ['refresh_token' => $json['refresh_token']]);
$response->assertStatus(200);
$json = $response->json();
$this->assertTrue(!empty($json['access_token']));
$this->assertTrue($json['access_token'] != $token);
- $this->assertEquals(\config('jwt.ttl') * 60, $json['expires_in']);
+ $this->assertEquals(\config('auth.token_expiry_minutes') * 60, $json['expires_in']);
$this->assertEquals('bearer', $json['token_type']);
$new_token = $json['access_token'];

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 4, 6:48 AM (21 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18828424
Default Alt Text
D2494.1775285285.diff (32 KB)

Event Timeline