Page MenuHomePhorge

D5331.1775362501.diff
No OneTemporary

Authored By
Unknown
Size
15 KB
Referenced Files
None
Subscribers
None

D5331.1775362501.diff

diff --git a/src/app/Http/Controllers/API/V4/Admin/UsersController.php b/src/app/Http/Controllers/API/V4/Admin/UsersController.php
--- a/src/app/Http/Controllers/API/V4/Admin/UsersController.php
+++ b/src/app/Http/Controllers/API/V4/Admin/UsersController.php
@@ -2,7 +2,6 @@
namespace App\Http\Controllers\API\V4\Admin;
-use App\Auth\OAuth;
use App\Domain;
use App\Entitlement;
use App\EventLog;
@@ -20,8 +19,6 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
-use League\OAuth2\Server\AuthorizationServer;
-use Psr\Http\Message\ServerRequestInterface;
class UsersController extends \App\Http\Controllers\API\V4\UsersController
{
@@ -158,35 +155,6 @@
return response()->json($result);
}
- /**
- * Webmail Login-As session initialization (via SSO)
- *
- * @param string $id The account to log into
- * @param ServerRequestInterface $psrRequest PSR request
- * @param Request $request The API request
- * @param AuthorizationServer $server Authorization server
- *
- * @return JsonResponse
- */
- public function loginAs($id, ServerRequestInterface $psrRequest, Request $request, AuthorizationServer $server)
- {
- $user = User::find($id);
-
- if (!$this->checkTenant($user)) {
- return $this->errorResponse(404);
- }
-
- if ($this->guard()->user()->role != User::ROLE_ADMIN) {
- return $this->errorResponse(403);
- }
-
- if (!$user->hasSku('mailbox')) {
- return $this->errorResponse(403);
- }
-
- return OAuth::loginAs($user, $psrRequest, $request, $server);
- }
-
/**
* Reset 2-Factor Authentication for the user
*
diff --git a/src/app/Http/Controllers/API/V4/UsersController.php b/src/app/Http/Controllers/API/V4/UsersController.php
--- a/src/app/Http/Controllers/API/V4/UsersController.php
+++ b/src/app/Http/Controllers/API/V4/UsersController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\API\V4;
+use App\Auth\OAuth;
use App\Domain;
use App\Entitlement;
use App\Group;
@@ -25,6 +26,8 @@
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
+use League\OAuth2\Server\AuthorizationServer;
+use Psr\Http\Message\ServerRequestInterface;
class UsersController extends RelationController
{
@@ -181,6 +184,39 @@
]);
}
+ /**
+ * Webmail Login-As session initialization (via SSO)
+ *
+ * @param string $id The account to log into
+ * @param ServerRequestInterface $psrRequest PSR request
+ * @param Request $request The API request
+ * @param AuthorizationServer $server Authorization server
+ *
+ * @return JsonResponse
+ */
+ public function loginAs($id, ServerRequestInterface $psrRequest, Request $request, AuthorizationServer $server)
+ {
+ if (!\config('app.with_loginas')) {
+ return $this->errorResponse(404);
+ }
+
+ $user = User::find($id);
+
+ if (!$this->checkTenant($user)) {
+ return $this->errorResponse(404);
+ }
+
+ if (!$this->guard()->user()->canDelete($user)) {
+ return $this->errorResponse(403);
+ }
+
+ if (!$user->hasSku('mailbox')) {
+ return $this->errorResponse(403);
+ }
+
+ return OAuth::loginAs($user, $psrRequest, $request, $server);
+ }
+
/**
* Display information on the user account specified by $id.
*
@@ -268,6 +304,7 @@
'enableWalletMandates' => $isController,
'enableWalletPayments' => $isController && $plan?->mode != Plan::MODE_MANDATE,
'enableCompanionapps' => $hasBeta && \config('app.with_companion_app'),
+ 'enableLoginAs' => $isController && \config('app.with_loginas'),
];
return array_merge($process, $result);
diff --git a/src/config/app.php b/src/config/app.php
--- a/src/config/app.php
+++ b/src/config/app.php
@@ -255,7 +255,7 @@
'with_subscriptions' => (bool) env('APP_WITH_SUBSCRIPTIONS', true),
'with_wallet' => (bool) env('APP_WITH_WALLET', true),
'with_delegation' => (bool) env('APP_WITH_DELEGATION', true),
-
+ 'with_loginas' => (bool) env('APP_WITH_LOGINAS', false),
'with_distlists' => (bool) env('APP_WITH_DISTLISTS', true),
'with_shared_folders' => (bool) env('APP_WITH_SHARED_FOLDERS', true),
'with_resources' => (bool) env('APP_WITH_RESOURCES', true),
diff --git a/src/resources/vue/Admin/User.vue b/src/resources/vue/Admin/User.vue
--- a/src/resources/vue/Admin/User.vue
+++ b/src/resources/vue/Admin/User.vue
@@ -83,9 +83,6 @@
<btn id="button-resync" class="btn-outline-primary" @click="resyncUser">
{{ $t('btn.resync') }}
</btn>
- <btn id="button-login-as" class="btn-outline-primary" @click="loginAs">
- {{ $t('user.login-as') }}
- </btn>
</div>
</div>
</div>
@@ -553,14 +550,6 @@
this.$root.clearFormValidation($('#email-dialog'))
this.$refs.emailDialog.show()
},
- loginAs() {
- axios.post('/api/v4/users/' + this.user.id + '/login-as')
- .then(response => {
- if (response.data.redirectUrl) {
- window.open(response.data.redirectUrl)
- }
- })
- },
setMandateState() {
let mandate = this.wallet.mandate
if (mandate && mandate.id) {
diff --git a/src/resources/vue/User/Info.vue b/src/resources/vue/User/Info.vue
--- a/src/resources/vue/User/Info.vue
+++ b/src/resources/vue/User/Info.vue
@@ -86,6 +86,9 @@
<subscription-select v-if="user.id" class="col-sm-8 pt-sm-1" :object="user" ref="skus"></subscription-select>
</div>
<btn class="btn-primary" type="submit" icon="check">{{ $t('btn.submit') }}</btn>
+ <btn id="button-login-as" class="btn-outline-secondary float-end" @click="loginAs" v-if="$route.name != 'settings' && $root.hasPermission('loginAs')">
+ {{ $t('user.login-as') }}
+ </btn>
</form>
</div>
<div v-if="Object.keys(settingsSections).length > 0" class="tab-pane" id="settings" role="tabpanel" aria-labelledby="tab-settings">
@@ -619,7 +622,15 @@
}
}
})
- }
+ },
+ loginAs() {
+ axios.post('/api/v4/users/' + this.user_id + '/login-as')
+ .then(response => {
+ if (response.data.redirectUrl) {
+ window.open(response.data.redirectUrl)
+ }
+ })
+ }
}
}
</script>
diff --git a/src/routes/api.php b/src/routes/api.php
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -129,7 +129,6 @@
Route::apiResource('users', API\V4\Admin\UsersController::class);
Route::get('users/{id}/discounts', [API\V4\Admin\DiscountsController::class, 'userDiscounts']);
- Route::post('users/{id}/login-as', [API\V4\Admin\UsersController::class, 'loginAs']);
Route::post('users/{id}/reset-2fa', [API\V4\Admin\UsersController::class, 'reset2FA']);
Route::post('users/{id}/reset-geolock', [API\V4\Admin\UsersController::class, 'resetGeoLock']);
Route::post('users/{id}/resync', [API\V4\Admin\UsersController::class, 'resync']);
@@ -262,6 +261,7 @@
Route::apiResource('users', API\V4\UsersController::class);
Route::post('users/{id}/config', [API\V4\UsersController::class, 'setConfig']);
+ Route::post('users/{id}/login-as', [API\V4\UsersController::class, 'loginAs']);
Route::get('users/{id}/skus', [API\V4\UsersController::class, 'skus']);
Route::get('users/{id}/status', [API\V4\UsersController::class, 'status']);
diff --git a/src/tests/Feature/Controller/Admin/UsersTest.php b/src/tests/Feature/Controller/Admin/UsersTest.php
--- a/src/tests/Feature/Controller/Admin/UsersTest.php
+++ b/src/tests/Feature/Controller/Admin/UsersTest.php
@@ -319,45 +319,6 @@
$this->assertTrue($json['list'][0]['isDeleted']);
}
- /**
- * Test login-as request (POST /api/v4/users/<user-id>/login-as)
- */
- public function testLoginAs(): void
- {
- Queue::fake();
-
- $user = $this->getTestUser('UsersControllerTest1@userscontroller.com');
- $admin = $this->getTestUser('jeroen@jeroen.jeroen');
-
- // Test non-existing user
- $response = $this->actingAs($admin)->post("/api/v4/users/123456/login-as", []);
- $response->assertStatus(404);
-
- // Test unauthorized access to admin API
- $response = $this->actingAs($user)->post("/api/v4/users/{$user->id}/login-as", []);
- $response->assertStatus(403);
-
- // Test user w/o mailbox SKU
- $response = $this->actingAs($admin)->post("/api/v4/users/{$user->id}/login-as", []);
- $response->assertStatus(403);
-
- $sku = Sku::withObjectTenantContext($user)->where(['title' => 'mailbox'])->first();
- $user->assignSku($sku);
-
- // Test login-as
- $response = $this->actingAs($admin)->post("/api/v4/users/{$user->id}/login-as", []);
- $response->assertStatus(200);
-
- $json = $response->json();
-
- parse_str(parse_url($json['redirectUrl'], \PHP_URL_QUERY), $params);
-
- $this->assertSame('success', $json['status']);
- $this->assertSame('1', $params['helpdesk']);
-
- // TODO: Assert the Roundcube cache entry
- }
-
/**
* Test reseting 2FA (POST /api/v4/users/<user-id>/reset-2fa)
*/
diff --git a/src/tests/Feature/Controller/User/DelegationTest.php b/src/tests/Feature/Controller/User/DelegationTest.php
--- a/src/tests/Feature/Controller/User/DelegationTest.php
+++ b/src/tests/Feature/Controller/User/DelegationTest.php
@@ -33,7 +33,7 @@
Queue::fake();
$john = $this->getTestUser('john@kolab.org');
- $jane = $this->getTestUser('jane@kolab.org');
+ $joe = $this->getTestUser('joe@kolab.org');
$jack = $this->getTestUser('jack@kolab.org');
$ned = $this->getTestUser('ned@kolab.org');
@@ -66,7 +66,7 @@
$this->assertSame(["The specified email address is not a valid delegation target."], $json['errors']['email']);
// Invalid options
- $post = ['email' => $jane->email, 'options' => ['ufo' => 're']];
+ $post = ['email' => $joe->email, 'options' => ['ufo' => 're']];
$response = $this->actingAs($john)->post("api/v4/users/{$john->id}/delegations", $post);
$response->assertStatus(422);
@@ -76,7 +76,7 @@
$this->assertSame(["The specified delegation options are invalid."], $json['errors']['options']);
// Valid input
- $post = ['email' => $jane->email, 'options' => ['mail' => 'read-only']];
+ $post = ['email' => $joe->email, 'options' => ['mail' => 'read-only']];
$response = $this->actingAs($john)->post("api/v4/users/{$john->id}/delegations", $post);
$response->assertStatus(200);
@@ -86,7 +86,7 @@
$this->assertSame("Delegation created successfully.", $json['message']);
$delegatee = $john->delegatees()->first();
- $this->assertSame($jane->email, $delegatee->email);
+ $this->assertSame($joe->email, $delegatee->email);
$this->assertSame(['mail' => 'read-only'], $delegatee->delegation->options);
// Valid input (action taken by another wallet controller)
@@ -108,13 +108,13 @@
Queue::fake();
$john = $this->getTestUser('john@kolab.org');
- $jane = $this->getTestUser('jane@kolab.org');
+ $joe = $this->getTestUser('joe@kolab.org');
$jack = $this->getTestUser('jack@kolab.org');
$ned = $this->getTestUser('ned@kolab.org');
$user = $this->getTestUser('deleted@kolabnow.com');
Delegation::create(['user_id' => $john->id, 'delegatee_id' => $jack->id]);
- Delegation::create(['user_id' => $john->id, 'delegatee_id' => $jane->id, 'options' => ['mail' => 'r']]);
+ Delegation::create(['user_id' => $john->id, 'delegatee_id' => $joe->id, 'options' => ['mail' => 'r']]);
// Test unauth access
$response = $this->get("api/v4/users/{$john->id}/delegations");
@@ -138,7 +138,7 @@
$this->assertSame(2, $json['count']);
$this->assertSame($jack->email, $json['list'][0]['email']);
$this->assertSame([], $json['list'][0]['options']);
- $this->assertSame($jane->email, $json['list'][1]['email']);
+ $this->assertSame($joe->email, $json['list'][1]['email']);
$this->assertSame(['mail' => 'r'], $json['list'][1]['options']);
// Test request made by the delegators wallet controller
diff --git a/src/tests/Feature/Controller/UsersTest.php b/src/tests/Feature/Controller/UsersTest.php
--- a/src/tests/Feature/Controller/UsersTest.php
+++ b/src/tests/Feature/Controller/UsersTest.php
@@ -286,6 +286,66 @@
// TODO: Test paging
}
+ /**
+ * Test login-as request (POST /api/v4/users/<user-id>/login-as)
+ */
+ public function testLoginAs(): void
+ {
+ Queue::fake();
+
+ $john = $this->getTestUser('john@kolab.org');
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jane = $this->getTestUser('jane@kolabnow.com');
+ $ned = $this->getTestUser('ned@kolab.org');
+ $wallet = $john->wallet();
+
+ \config(['app.with_loginas' => true]);
+
+ // Test non-existing user
+ $response = $this->actingAs($john)->post("/api/v4/users/123456/login-as", []);
+ $response->assertStatus(404);
+
+ // Test unauthorized access
+ $response = $this->actingAs($jack)->post("/api/v4/users/{$ned->id}/login-as", []);
+ $response->assertStatus(403);
+
+ // Test unauthorized access (Jane is not in the same account yet)
+ $response = $this->actingAs($john)->post("/api/v4/users/{$jane->id}/login-as", []);
+ $response->assertStatus(403);
+
+ $sku = Sku::withObjectTenantContext($john)->where(['title' => 'storage'])->first();
+ $jane->assignSku($sku, 1, $wallet);
+
+ // Test user w/o mailbox SKU
+ $response = $this->actingAs($john)->post("/api/v4/users/{$jane->id}/login-as", []);
+ $response->assertStatus(403);
+
+ $sku = Sku::withObjectTenantContext($john)->where(['title' => 'mailbox'])->first();
+ $jane->assignSku($sku, 1, $wallet);
+
+ // Test login-as
+ $response = $this->actingAs($john)->post("/api/v4/users/{$jane->id}/login-as", []);
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ parse_str(parse_url($json['redirectUrl'], \PHP_URL_QUERY), $params);
+
+ $this->assertSame('success', $json['status']);
+ $this->assertSame('1', $params['helpdesk']);
+
+ // TODO: Assert the Roundcube cache entry
+
+ // Test login-as acting as wallet controller
+ $response = $this->actingAs($ned)->post("/api/v4/users/{$jane->id}/login-as", []);
+ $response->assertStatus(200);
+
+ // Test with disabled feature
+ \config(['app.with_loginas' => false]);
+ $response = $this->actingAs($john)->post("/api/v4/users/{$jack->id}/login-as", []);
+ $response->assertStatus(404);
+ }
+
/**
* Test fetching user data/profile (GET /api/v4/users/<user-id>)
*/

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 5, 4:15 AM (22 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18832311
Default Alt Text
D5331.1775362501.diff (15 KB)

Event Timeline