Page MenuHomePhorge

D1435.1775545243.diff
No OneTemporary

Authored By
Unknown
Size
11 KB
Referenced Files
None
Subscribers
None

D1435.1775545243.diff

diff --git a/src/.env.example b/src/.env.example
--- a/src/.env.example
+++ b/src/.env.example
@@ -98,6 +98,7 @@
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
JWT_SECRET=
+JWT_TTL=60
COMPANY_NAME=
COMPANY_ADDRESS=
diff --git a/src/app/Auth/LDAPUserProvider.php b/src/app/Auth/LDAPUserProvider.php
--- a/src/app/Auth/LDAPUserProvider.php
+++ b/src/app/Auth/LDAPUserProvider.php
@@ -14,21 +14,7 @@
class LDAPUserProvider extends EloquentUserProvider implements UserProvider
{
/**
- * Retrieve the user by its ID.
- *
- * @param string $identifier The unique ID for the user to attempt to retrieve.
- *
- * @return \Illuminate\Contracts\Auth\Authenticatable|null
- */
- public function retrieveById($identifier)
- {
- return parent::retrieveById($identifier);
- }
-
- /**
- * Retrieve the user by its credentials.
- *
- * Please note that this function also validates the password.
+ * Retrieve the user by its credentials (email).
*
* @param array $credentials An array containing the email and password.
*
@@ -36,18 +22,12 @@
*/
public function retrieveByCredentials(array $credentials)
{
- $entries = User::where('email', '=', $credentials['email']);
+ $entries = User::where('email', '=', $credentials['email'])->get();
$count = $entries->count();
if ($count == 1) {
- $user = $entries->select(['id', 'email', 'password', 'password_ldap'])->first();
-
- if (!$this->validateCredentials($user, $credentials)) {
- return null;
- }
-
- return $user;
+ return $entries->first();
}
if ($count > 1) {
@@ -103,12 +83,10 @@
}
}
- // TODO: update last login time
- // TODO: Update password if necessary, examine whether writing to
- // user->password is sufficient?
if ($authenticated) {
\Log::info("Successful authentication for {$user->email}");
+ // TODO: update last login time
if (empty($user->password) || empty($user->password_ldap)) {
$user->password = $credentials['password'];
$user->save();
diff --git a/src/app/Http/Kernel.php b/src/app/Http/Kernel.php
--- a/src/app/Http/Kernel.php
+++ b/src/app/Http/Kernel.php
@@ -30,13 +30,13 @@
*/
protected $middlewareGroups = [
'web' => [
- \App\Http\Middleware\EncryptCookies::class,
- \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
- \Illuminate\Session\Middleware\StartSession::class,
+ // \App\Http\Middleware\EncryptCookies::class,
+ // \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
+ // \Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
- \Illuminate\View\Middleware\ShareErrorsFromSession::class,
- \App\Http\Middleware\VerifyCsrfToken::class,
- \Illuminate\Routing\Middleware\SubstituteBindings::class,
+ // \Illuminate\View\Middleware\ShareErrorsFromSession::class,
+ // \App\Http\Middleware\VerifyCsrfToken::class,
+ // \Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
diff --git a/src/app/User.php b/src/app/User.php
--- a/src/app/User.php
+++ b/src/app/User.php
@@ -653,12 +653,7 @@
*/
public function setPasswordLdapAttribute($password)
{
- if (!empty($password)) {
- $this->attributes['password'] = bcrypt($password, [ "rounds" => 12 ]);
- $this->attributes['password_ldap'] = '{SSHA512}' . base64_encode(
- pack('H*', hash('sha512', $password))
- );
- }
+ $this->setPasswordAttribute($password);
}
/**
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
@@ -50,17 +50,40 @@
return false
},
// Set user state to "logged in"
- loginUser(token, dashboard) {
- store.commit('logoutUser') // destroy old state data
- store.commit('loginUser')
- localStorage.setItem('token', token)
- axios.defaults.headers.common.Authorization = 'Bearer ' + token
+ loginUser(response, dashboard, update) {
+ if (!update) {
+ store.commit('logoutUser') // destroy old state data
+ store.commit('loginUser')
+ }
+
+ localStorage.setItem('token', response.access_token)
+ axios.defaults.headers.common.Authorization = 'Bearer ' + response.access_token
if (dashboard !== false) {
this.$router.push(store.state.afterLogin || { name: 'dashboard' })
}
store.state.afterLogin = null
+
+ // Refresh the token before it expires
+ let timeout = response.expires_in || 0
+
+ // We'll refresh 60 seconds before the token expires
+ // or immediately when we have no expiration time (on token re-use)
+ if (timeout > 60) {
+ timeout -= 60
+ }
+
+ // TODO: We probably should try a few times in case of an error
+ // TODO: We probably should prevent axios from doing any requests
+ // while the token is being refreshed
+
+ this.refreshTimeout = setTimeout(() => {
+ axios.post('/api/auth/refresh').then(response => {
+ this.loginUser(response.data, false, true)
+ })
+
+ }, timeout * 1000)
},
// Set user state to "not logged in"
logoutUser() {
@@ -68,6 +91,7 @@
localStorage.setItem('token', '')
delete axios.defaults.headers.common.Authorization
this.$router.push({ name: 'login' })
+ clearTimeout(this.refreshTimeout)
},
// Display "loading" overlay inside of the specified element
addLoader(elem) {
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
@@ -21,7 +21,7 @@
.then(response => {
this.isLoading = false
this.$root.stopLoading()
- this.$root.loginUser(token, false)
+ this.$root.loginUser({ access_token: token }, false)
this.$store.state.authInfo = response.data
})
.catch(error => {
diff --git a/src/resources/vue/Login.vue b/src/resources/vue/Login.vue
--- a/src/resources/vue/Login.vue
+++ b/src/resources/vue/Login.vue
@@ -68,7 +68,7 @@
secondfactor: this.secondFactor
}).then(response => {
// login user and redirect to dashboard
- this.$root.loginUser(response.data.access_token)
+ this.$root.loginUser(response.data)
})
}
}
diff --git a/src/resources/vue/PasswordReset.vue b/src/resources/vue/PasswordReset.vue
--- a/src/resources/vue/PasswordReset.vue
+++ b/src/resources/vue/PasswordReset.vue
@@ -129,7 +129,7 @@
password_confirmation: this.password_confirmation
}).then(response => {
// auto-login and goto dashboard
- this.$root.loginUser(response.data.access_token)
+ this.$root.loginUser(response.data)
})
},
// Moves the user a step back in registration form
diff --git a/src/resources/vue/Signup.vue b/src/resources/vue/Signup.vue
--- a/src/resources/vue/Signup.vue
+++ b/src/resources/vue/Signup.vue
@@ -233,7 +233,7 @@
voucher: this.voucher
}).then(response => {
// auto-login and goto dashboard
- this.$root.loginUser(response.data.access_token)
+ this.$root.loginUser(response.data)
})
},
// Moves the user a step back in registration form
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
@@ -125,9 +125,42 @@
$response->assertStatus(401);
}
+ /**
+ * Test /api/auth/refresh
+ */
public function testRefresh(): void
{
- // TODO
- $this->markTestIncomplete();
+ // Request with no token, testing that it requires auth
+ $response = $this->post("api/auth/refresh");
+ $response->assertStatus(401);
+
+ // Test the same using JSON mode
+ $response = $this->json('POST', "api/auth/refresh", []);
+ $response->assertStatus(401);
+
+ // Login the user to get a valid token
+ $post = ['email' => 'john@kolab.org', 'password' => 'simple123'];
+ $response = $this->post("api/auth/login", $post);
+ $response->assertStatus(200);
+ $json = $response->json();
+ $token = $json['access_token'];
+
+ // Request with a valid token
+ $response = $this->withHeaders(['Authorization' => 'Bearer ' . $token])->post("api/auth/refresh");
+ $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('bearer', $json['token_type']);
+ $new_token = $json['access_token'];
+
+ // TODO: Shall we invalidate the old token?
+
+ // And if the new token is working
+ $response = $this->withHeaders(['Authorization' => 'Bearer ' . $new_token])->get("api/auth/info");
+ $response->assertStatus(200);
}
}
diff --git a/src/tests/Unit/UserTest.php b/src/tests/Unit/UserTest.php
--- a/src/tests/Unit/UserTest.php
+++ b/src/tests/Unit/UserTest.php
@@ -8,9 +8,41 @@
class UserTest extends TestCase
{
/**
+ * Test User password mutator
+ */
+ public function testSetPasswordAttribute(): void
+ {
+ $user = new User(['email' => 'user@email.com']);
+
+ $user->password = 'test';
+
+ $ssh512 = "{SSHA512}7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ"
+ . "6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w==";
+
+ $this->assertRegExp('/^\$2y\$12\$[0-9a-zA-Z\/.]{53}$/', $user->password);
+ $this->assertSame($ssh512, $user->password_ldap);
+ }
+
+ /**
+ * Test User password mutator
+ */
+ public function testSetPasswordLdapAttribute(): void
+ {
+ $user = new User(['email' => 'user@email.com']);
+
+ $user->password_ldap = 'test';
+
+ $ssh512 = "{SSHA512}7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ"
+ . "6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w==";
+
+ $this->assertRegExp('/^\$2y\$12\$[0-9a-zA-Z\/.]{53}$/', $user->password);
+ $this->assertSame($ssh512, $user->password_ldap);
+ }
+
+ /**
* Test basic User funtionality
*/
- public function testUserStatus()
+ public function testStatus(): void
{
$statuses = [
User::STATUS_NEW,
@@ -43,7 +75,7 @@
/**
* Test setStatusAttribute exception
*/
- public function testUserStatusInvalid(): void
+ public function testStatusInvalid(): void
{
$this->expectException(\Exception::class);

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 7, 7:00 AM (1 d, 6 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18821584
Default Alt Text
D1435.1775545243.diff (11 KB)

Event Timeline