Skip to content

Commit 71f869e

Browse files
authored
feat: add user to group endpoint (#87)
* feat: add user to group endpoint Signed-off-by: romanetar <roman_ag@hotmail.com> * feat: add user to group endpoint Signed-off-by: romanetar <roman_ag@hotmail.com> * feat: ensure service account middleware Signed-off-by: romanetar <roman_ag@hotmail.com> --------- Signed-off-by: romanetar <roman_ag@hotmail.com>
1 parent 56325c7 commit 71f869e

File tree

13 files changed

+348
-2
lines changed

13 files changed

+348
-2
lines changed

app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@
1313
**/
1414

1515
use App\Http\Controllers\GetAllTrait;
16+
use App\Http\Controllers\Traits\RequestProcessor;
17+
use App\Http\Controllers\UserGroupsValidationRulesFactory;
1618
use App\Http\Controllers\UserValidationRulesFactory;
19+
use App\Http\Exceptions\HTTP403ForbiddenException;
1720
use App\Http\Utils\HTMLCleaner;
1821
use App\ModelSerializers\SerializerRegistry;
1922
use Auth\Repositories\IUserRepository;
23+
use Illuminate\Http\JsonResponse;
2024
use Illuminate\Http\Request as LaravelRequest;
25+
use Illuminate\Support\Facades\App;
2126
use Illuminate\Support\Facades\Auth;
2227
use Illuminate\Support\Facades\Request;
2328
use Illuminate\Support\Facades\Log;
@@ -27,6 +32,7 @@
2732
use models\exceptions\ValidationException;
2833
use OAuth2\Builders\IdTokenBuilder;
2934
use OAuth2\IResourceServerContext;
35+
use OAuth2\Models\IClient;
3036
use OAuth2\Repositories\IClientRepository;
3137
use OAuth2\ResourceServer\IUserService;
3238
use Utils\Http\HttpContentType;
@@ -41,6 +47,8 @@ final class OAuth2UserApiController extends OAuth2ProtectedController
4147
{
4248
use GetAllTrait;
4349

50+
use RequestProcessor;
51+
4452
protected function getAllSerializerType(): string
4553
{
4654
return SerializerRegistry::SerializerType_Private;
@@ -324,4 +332,28 @@ public function get($id)
324332
}
325333
}
326334

335+
/**
336+
* @param $user_id
337+
* @return JsonResponse|mixed
338+
*/
339+
public function updateUserGroups($user_id): mixed
340+
{
341+
return $this->processRequest(function() use($user_id) {
342+
if(!Request::isJson()) return $this->error400();
343+
344+
$payload = Request::json()->all();
345+
// Creates a Validator instance and validates the data.
346+
$validation = Validator::make($payload, UserGroupsValidationRulesFactory::build($payload));
347+
if ($validation->fails()) {
348+
$ex = new ValidationException();
349+
throw $ex->setMessages($validation->messages()->toArray());
350+
}
351+
$user_groups_payload = [
352+
"groups" => $payload["groups"],
353+
];
354+
$this->openid_user_service->update(intval($user_id), $user_groups_payload);
355+
return $this->updated();
356+
});
357+
}
358+
327359
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php namespace App\Http\Controllers;
2+
/**
3+
* Copyright 2025 OpenStack Foundation
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
**/
14+
use Auth\User;
15+
/**
16+
* Class UserGroupsValidationRulesFactory
17+
* @package App\Http\Controllers
18+
*/
19+
final class UserGroupsValidationRulesFactory
20+
{
21+
/**
22+
* @param array $data
23+
* @param false $update
24+
* @param User|null $currentUser
25+
* @return string[]
26+
*/
27+
public static function build(array $data, $update = false, ?User $currentUser = null){
28+
29+
if($update){
30+
return [
31+
'groups' => 'sometimes|int_array',
32+
];
33+
}
34+
35+
return [
36+
'groups' => 'required|int_array',
37+
];
38+
}
39+
}

app/Http/Kernel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,6 @@ class Kernel extends HttpKernel
7676
'openstackid.currentuser.serveradmin.json' => \App\Http\Middleware\CurrentUserIsOpenIdServerAdminJson::class,
7777
'oauth2.currentuser.allow.client.edition' => \App\Http\Middleware\CurrentUserCanEditOAuth2Client::class,
7878
'oauth2.currentuser.owns.client' => \App\Http\Middleware\CurrentUserOwnsOAuth2Client::class,
79+
'service.account' => \App\Http\Middleware\EnsureServiceAccount::class,
7980
];
8081
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php namespace App\Http\Middleware;
2+
3+
/**
4+
* Copyright 2025 OpenStack Foundation
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
**/
15+
16+
use Closure;
17+
use Illuminate\Support\Facades\App;
18+
use Illuminate\Support\Facades\Response;
19+
use OAuth2\IResourceServerContext;
20+
21+
final class EnsureServiceAccount
22+
{
23+
/**
24+
* @var IResourceServerContext
25+
*/
26+
private $context;
27+
28+
/**
29+
* EnsureServiceAccount constructor.
30+
* @param IResourceServerContext $context
31+
*/
32+
public function __construct(IResourceServerContext $context)
33+
{
34+
$this->context = $context;
35+
}
36+
37+
/**
38+
* @param $request
39+
* @param Closure $next
40+
* @return \Illuminate\Http\JsonResponse|mixed
41+
*/
42+
public function handle($request, Closure $next)
43+
{
44+
$application_type = $this->context->getApplicationType();
45+
if ($application_type != IResourceServerContext::ApplicationType_Service) {
46+
return Response::json(['error' => 'Only service accounts are allowed.'], 403);
47+
}
48+
return $next($request);
49+
}
50+
}

app/libs/OAuth2/IUserScopes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ interface IUserScopes
2929
const MeRead = 'me/read';
3030
const MeWrite = 'me/write';
3131
const Write = 'users/write';
32+
const UserGroupWrite = 'users/groups/write';
3233
}

app/libs/OpenId/Services/IUserService.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
use Illuminate\Http\UploadedFile;
1717
use models\exceptions\EntityNotFoundException;
1818
use models\exceptions\ValidationException;
19+
use models\utils\IEntity;
20+
1921
/**
2022
* Interface IUserService
2123
* @package OpenId\Services
@@ -72,6 +74,15 @@ public function saveProfileInfo($user_id, $show_pic, $show_full_name, $show_emai
7274
*/
7375
public function updateProfilePhoto($user_id, UploadedFile $file, $max_file_size = 10485760):User;
7476

77+
/**
78+
* @param int $id
79+
* @param array $payload
80+
* @return IEntity
81+
* @throws ValidationException
82+
* @throws EntityNotFoundException
83+
*/
84+
public function update(int $id, array $payload): IEntity;
85+
7586
/**
7687
* @param string $action
7788
* @param int $user_id

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"Database\\Seeders\\": "database/seeders/"
9090
},
9191
"files": [
92+
"app/Utils/helpers.php",
9293
"app/libs/Utils/Html/HtmlHelpers.php"
9394
]
9495
},
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php namespace Database\Migrations;
2+
/**
3+
* Copyright 2025 OpenStack Foundation
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
**/
14+
15+
use App\libs\OAuth2\IUserScopes;
16+
use Database\Seeders\SeedUtils;
17+
use Doctrine\Migrations\AbstractMigration;
18+
use Doctrine\DBAL\Schema\Schema as Schema;
19+
/**
20+
* Class Version20250805084926
21+
* @package Database\Migrations
22+
*/
23+
class Version20250805084926 extends AbstractMigration
24+
{
25+
/**
26+
* @param Schema $schema
27+
*/
28+
public function up(Schema $schema):void
29+
{
30+
SeedUtils::seedScopes([
31+
[
32+
'name' => IUserScopes::UserGroupWrite,
33+
'short_description' => 'Allows associate Users to Groups.',
34+
'description' => 'Allows associate Users to Groups.',
35+
'system' => false,
36+
'default' => false,
37+
'groups' => false,
38+
]
39+
], 'users');
40+
41+
SeedUtils::seedApiEndpoints('users', [
42+
[
43+
'name' => 'add-user-to-groups',
44+
'active' => true,
45+
'route' => '/api/v1/users/{id}/groups',
46+
'http_method' => 'PUT',
47+
'scopes' => [
48+
IUserScopes::UserGroupWrite
49+
],
50+
],
51+
]);
52+
}
53+
54+
/**
55+
* @param Schema $schema
56+
*/
57+
public function down(Schema $schema):void
58+
{
59+
60+
}
61+
}

database/seeds/ApiEndpointSeeder.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
* See the License for the specific language governing permissions and
1212
* limitations under the License.
1313
**/
14+
15+
use App\libs\OAuth2\IUserScopes;
1416
use Illuminate\Database\Seeder;
1517
use Illuminate\Support\Facades\DB;
1618
/**
@@ -119,6 +121,15 @@ private function seedUsersEndpoints()
119121
\App\libs\OAuth2\IUserScopes::MeWrite
120122
],
121123
],
124+
[
125+
'name' => 'add-user-to-groups',
126+
'active' => true,
127+
'route' => '/api/v1/users/{id}/groups',
128+
'http_method' => 'PUT',
129+
'scopes' => [
130+
\App\libs\OAuth2\IUserScopes::UserGroupWrite
131+
],
132+
],
122133
]
123134
);
124135
}

database/seeds/ApiScopeSeeder.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ private function seedUsersScopes(){
9191
'system' => false,
9292
'default' => false,
9393
'groups' => false,
94+
],
95+
[
96+
'name' => IUserScopes::UserGroupWrite,
97+
'short_description' => 'Allows associate Users to Groups',
98+
'description' => 'Allows associate Users to Groups',
99+
'system' => false,
100+
'default' => false,
101+
'groups' => false,
94102
]
95103
], 'users');
96104

0 commit comments

Comments
 (0)