|
@@ -0,0 +1,200 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Api\v1\Controllers;
|
|
|
+
|
|
|
+use App\Api\v1\Requests\UserManagerStoreRequest;
|
|
|
+use App\Api\v1\Requests\UserManagerUpdateRequest;
|
|
|
+use App\Api\v1\Resources\UserManagerResource;
|
|
|
+use App\Http\Controllers\Controller;
|
|
|
+use App\Models\User;
|
|
|
+use Illuminate\Http\Request;
|
|
|
+use Illuminate\Support\Facades\Hash;
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
+use Illuminate\Support\Facades\Password;
|
|
|
+use Laravel\Passport\TokenRepository;
|
|
|
+
|
|
|
+class UserManagerController extends Controller
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * Display all users.
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
|
|
|
+ */
|
|
|
+ public function index(Request $request)
|
|
|
+ {
|
|
|
+ return UserManagerResource::collection(User::all());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get a user
|
|
|
+ *
|
|
|
+ * @return \App\Api\v1\Resources\UserManagerResource
|
|
|
+ */
|
|
|
+ public function show(User $user)
|
|
|
+ {
|
|
|
+ return new UserManagerResource($user);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Reset user's password
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Http\JsonResponse
|
|
|
+ */
|
|
|
+ public function resetPassword(Request $request, User $user)
|
|
|
+ {
|
|
|
+ Log::info(sprintf('Password reset for User ID #%s requested by User ID #%s', $user->id, $request->user()->id));
|
|
|
+
|
|
|
+ $credentials = [
|
|
|
+ 'token' => $this->broker()->createToken($user),
|
|
|
+ 'email' => $user->email,
|
|
|
+ 'password' => $user->password,
|
|
|
+ ];
|
|
|
+
|
|
|
+ $response = $this->broker()->reset(
|
|
|
+ $credentials, function ($user) {
|
|
|
+ $user->resetPassword();
|
|
|
+ $user->save();
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ if ($response == Password::PASSWORD_RESET) {
|
|
|
+ Log::info(sprintf('Temporary password set for User ID #%s', $user->id));
|
|
|
+
|
|
|
+ $response = $this->broker()->sendResetLink(
|
|
|
+ ['email' => $credentials['email']]
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return response()->json([
|
|
|
+ 'message' => 'bad request',
|
|
|
+ 'reason' => is_string($response) ? __($response) : __('errors.no_pwd_reset_for_this_user_type')
|
|
|
+ ], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $response == Password::RESET_LINK_SENT
|
|
|
+ ? new UserManagerResource($user)
|
|
|
+ : response()->json([
|
|
|
+ 'message' => 'bad request',
|
|
|
+ 'reason' => __($response)
|
|
|
+ ], 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Store a newly created user in storage.
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Http\JsonResponse
|
|
|
+ */
|
|
|
+ public function store(UserManagerStoreRequest $request)
|
|
|
+ {
|
|
|
+ $validated = $request->validated();
|
|
|
+
|
|
|
+ $user = User::create([
|
|
|
+ 'name' => $validated['name'],
|
|
|
+ 'email' => $validated['email'],
|
|
|
+ 'password' => Hash::make($validated['password']),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ Log::info(sprintf('User ID #%s created by user ID #%s', $user->id, $request->user()->id));
|
|
|
+
|
|
|
+ if ($validated['is_admin']) {
|
|
|
+ $user->promoteToAdministrator();
|
|
|
+ $user->save();
|
|
|
+ Log::notice(sprintf('User ID #%s set as administrator at creation by user ID #%s', $user->id, $request->user()->id));
|
|
|
+ }
|
|
|
+
|
|
|
+ $user->refresh();
|
|
|
+
|
|
|
+ return (new UserManagerResource($user))
|
|
|
+ ->response()
|
|
|
+ ->setStatusCode(201);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Purge user's PATs.
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Http\JsonResponse
|
|
|
+ */
|
|
|
+ public function revokePATs(Request $request, User $user, TokenRepository $tokenRepository)
|
|
|
+ {
|
|
|
+ Log::info(sprintf('Deletion of all personal access tokens for User ID #%s requested by User ID #%s', $user->id, $request->user()->id));
|
|
|
+
|
|
|
+ $tokens = $tokenRepository->forUser($user->getAuthIdentifier());
|
|
|
+
|
|
|
+ $tokens->load('client')->filter(function ($token) {
|
|
|
+ return $token->client->personal_access_client && ! $token->revoked;
|
|
|
+ })->each(function ($token) {
|
|
|
+ $token->revoke();
|
|
|
+ });
|
|
|
+
|
|
|
+ Log::info(sprintf('All personal access tokens for User ID #%s have been revoked', $user->id));
|
|
|
+
|
|
|
+ return response()->json(null, 204);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Purge user's webauthn credentials.
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Http\JsonResponse
|
|
|
+ */
|
|
|
+ public function revokeWebauthnCredentials(Request $request, User $user)
|
|
|
+ {
|
|
|
+ Log::info(sprintf('Deletion of all security devices for User ID #%s requested by User ID #%s', $user->id, $request->user()->id));
|
|
|
+
|
|
|
+ $user->flushCredentials();
|
|
|
+
|
|
|
+ // WebauthnOnly user options need to be reset to prevent impossible login when
|
|
|
+ // no more registered device exists.
|
|
|
+ // See #110
|
|
|
+ if (blank($user->webAuthnCredentials()->WhereEnabled()->get())) {
|
|
|
+ $user['preferences->useWebauthnOnly'] = false;
|
|
|
+ $user->save();
|
|
|
+ Log::notice(sprintf('No more Webauthn credential for user ID #%s, useWebauthnOnly user preference reset to false', $user->id));
|
|
|
+ }
|
|
|
+
|
|
|
+ Log::info(sprintf('All security devices for User ID #%s have been revoked', $user->id));
|
|
|
+
|
|
|
+ return response()->json(null, 204);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Remove the specified user from storage.
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Http\JsonResponse
|
|
|
+ */
|
|
|
+ public function destroy(Request $request, User $user)
|
|
|
+ {
|
|
|
+ // This will delete the user and all its 2FAs & Groups thanks to the onCascadeDelete constrains.
|
|
|
+ // Deletion will not be done (and returns False) if the user is the only existing admin (see UserObserver clas)
|
|
|
+ return $user->delete() === false
|
|
|
+ ? response()->json([
|
|
|
+ 'message' => __('errors.cannot_delete_the_only_admin'),
|
|
|
+ ], 403)
|
|
|
+ : response()->json(null, 204);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Update a user
|
|
|
+ *
|
|
|
+ * @return \App\Api\v1\Resources\UserManagerResource
|
|
|
+ */
|
|
|
+ public function update(UserManagerUpdateRequest $request, User $user)
|
|
|
+ {
|
|
|
+ $user->promoteToAdministrator($request->validated('is_admin'));
|
|
|
+ $user->save();
|
|
|
+
|
|
|
+ Log::info(sprintf('User ID #%s set is_admin=%s for User ID #%s', $request->user()->id, $user->isAdministrator(), $user->id));
|
|
|
+
|
|
|
+ return new UserManagerResource($user);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get the broker to be used during password reset.
|
|
|
+ *
|
|
|
+ * @return \Illuminate\Contracts\Auth\PasswordBroker|\Illuminate\Auth\Passwords\PasswordBroker
|
|
|
+ */
|
|
|
+ protected function broker()
|
|
|
+ {
|
|
|
+ return Password::broker();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|