Complete the documentation

Return a validation code on the admin account creation endpoint if the validation is set to false
Move some endpoints to be more consistant
Enforce validated accounts for authenticated endpoints
Bump the package version
This commit is contained in:
Timothée Jaussoin 2021-01-14 14:29:16 +01:00
parent 70463ae687
commit 539cf21269
7 changed files with 56 additions and 23 deletions

View file

@ -21,11 +21,13 @@ namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Carbon\Carbon;
use App\Account;
use App\Password;
use App\Helpers\Utils;
use App\Http\Controllers\Account\AuthenticateController as WebAuthenticateController;
class AccountController extends Controller
{
@ -87,6 +89,11 @@ class AccountController extends Controller
$account->ip_address = $request->ip();
$account->creation_time = Carbon::now();
$account->user_agent = config('app.name');
if (!$request->has('activated') || !(bool)$request->has('activated')) {
$account->confirmation_key = Str::random(WebAuthenticateController::$emailCodeSize);
}
$account->save();
$password = new Password;

View file

@ -56,6 +56,11 @@ class AuthenticateDigestOrKey
->where('domain', $domain)
->firstOrFail();
// Check if activated
if (!$account->activated) {
return $this->generateUnauthorizedResponse($account);
}
// Key authentication
if ($request->header('x-api-key')) {
if ($account->apiKey

View file

@ -36,6 +36,7 @@ class AccountFactory extends Factory
'user_agent' => $this->faker->userAgent,
'ip_address' => $this->faker->ipv4,
'creation_time' => $this->faker->dateTime,
'activated' => true
];
}
}

View file

@ -48,11 +48,13 @@ For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the auth
<h2>Endpoints</h2>
<h3>Ping</h3>
<h3>Public endpoints</h3>
<h4><code>GET /ping</code></h4>
<p>Returns <code>pong</code></p>
<h4>Accounts</h4>
<h4><code>GET /accounts/{sip}/info</code></h4>
<p>Retrieve public information about the account.</p>
<p>Return <code>404</code> if the account doesn't exists.</p>
@ -73,19 +75,23 @@ For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the auth
<li><code>code</code> the PIN code</li>
</ul>
<h3>Accounts (User)</h3>
<h3>User authenticated endpoints</h3>
<p>Those endpoints are authenticated and requires an activated account.</p>
<h4><code>GET /accounts/me</code></h4>
<p>Retrieve the account information.</p>
<h4><code>POST /accounts/email/request</code></h4>
<h4><code>DELETE /accounts/me</code></h4>
<p>Delete the account.</p>
<h4><code>POST /accounts/me/email/request</code></h4>
<p>Change the account email. An email will be sent to the new email address to confirm the operation.</p>
<p>JSON parameters:</p>
<ul>
<li><code>email</code> the new email address</li>
</ul>
<h4><code>POST /accounts/password</code></h4>
<h4><code>POST /accounts/me/password</code></h4>
<p>Change the account password.</p>
<p>JSON parameters:</p>
<ul>
@ -94,19 +100,22 @@ For the moment only DIGEST-MD5 and DIGEST-SHA-256 are supported through the auth
<li><code>password</code> required, the new password</li>
</ul>
<h3>Devices</h3>
<h4>Devices</h4>
<h4><code>GET /devices</code></h4>
<h4><code>GET /accounts/me/devices</code></h4>
<p>Return the user registered devices.</p>
<h4><code>DELETE /devices/{uuid}</code></h4>
<h4><code>DELETE /accounts/me/devices/{uuid}</code></h4>
<p>Remove one of the user registered devices.</p>
<h3>Accounts (Administrator)</h3>
<h3>Admin endpoints</h3>
<p>Those endpoints are authenticated and requires an admin account.</p>
<h4><code>POST /accounts</code></h4>
<p>To create an account directly from the API.</p>
<p>If <code>activated</code> is set to <code>false</code> a random generated <code>confirmation_key</code> will be returned to allow further activation using the public endpoints.</p>
<p>JSON parameters:</p>
<ul>
<li><code>username</code> unique username, minimum 6 characters</li>

View file

@ -34,11 +34,11 @@ Route::group(['middleware' => ['auth.digest_or_key']], function () {
Route::get('accounts/me', 'Api\AccountController@show');
Route::delete('accounts/me', 'Api\AccountController@delete');
Route::get('devices', 'Api\DeviceController@index');
Route::delete('devices/{uuid}', 'Api\DeviceController@destroy');
Route::get('accounts/me/devices', 'Api\DeviceController@index');
Route::delete('accounts/me/devices/{uuid}', 'Api\DeviceController@destroy');
Route::post('accounts/email/request', 'Api\EmailController@requestUpdate');
Route::post('accounts/password', 'Api\PasswordController@update');
Route::post('accounts/me/email/request', 'Api\EmailController@requestUpdate');
Route::post('accounts/me/password', 'Api\PasswordController@update');
Route::group(['middleware' => ['auth.admin']], function () {
Route::get('accounts/{id}/activate', 'Api\Admin\AccountController@activate');

View file

@ -107,8 +107,10 @@ class AccountApiTest extends TestCase
'id' => 2,
'username' => $username,
'domain' => $domain,
'activated' => false,
'activated' => false
]);
$this->assertFalse(empty($response1['confirmation_key']));
}
public function testUsernameNoDomain()
@ -177,12 +179,16 @@ class AccountApiTest extends TestCase
'domain' => config('app.sip_domain'),
'activated' => true,
]);
$this->assertTrue(empty($response1['confirmation_key']));
}
public function testSimpleAccount()
{
$password = Password::factory()->create();
$password->account->activated = false;
$password->account->generateApiKey();
$password->account->save();
/**
* Public information
@ -193,6 +199,9 @@ class AccountApiTest extends TestCase
'activated' => false
]);
$password->account->activated = true;
$password->account->save();
/**
* Retrieve the authenticated account
*/
@ -201,7 +210,7 @@ class AccountApiTest extends TestCase
->assertStatus(200)
->assertJson([
'username' => $password->account->username,
'activated' => false
'activated' => true
]);
/**
@ -224,6 +233,7 @@ class AccountApiTest extends TestCase
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->confirmation_key = $confirmationKey;
$password->account->activated = false;
$password->account->save();
$this->get($this->route.'/'.$password->account->identifier.'/info')
@ -269,6 +279,7 @@ class AccountApiTest extends TestCase
$password = Password::factory()->create();
$password->account->generateApiKey();
$password->account->confirmation_key = $confirmationKey;
$password->account->activated = false;
$password->account->save();
$this->get($this->route.'/'.$password->account->identifier.'/info')
@ -298,21 +309,21 @@ class AccountApiTest extends TestCase
// Bad email
$this->keyAuthenticated($password->account)
->json($this->method, $this->route.'/email/request', [
->json($this->method, $this->route.'/me/email/request', [
'email' => 'gnap'
])
->assertStatus(422);
// Same email
$this->keyAuthenticated($password->account)
->json($this->method, $this->route.'/email/request', [
->json($this->method, $this->route.'/me/email/request', [
'email' => $password->account->email
])
->assertStatus(422);
// Correct email
$this->keyAuthenticated($password->account)
->json($this->method, $this->route.'/email/request', [
->json($this->method, $this->route.'/me/email/request', [
'email' => $newEmail
])
->assertStatus(200);
@ -339,7 +350,7 @@ class AccountApiTest extends TestCase
// Wrong algorithm
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/password', [
->json($this->method, $this->route.'/me/password', [
'algorithm' => '123',
'password' => $password
])
@ -350,7 +361,7 @@ class AccountApiTest extends TestCase
// Fresh password without an old one
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/password', [
->json($this->method, $this->route.'/me/password', [
'algorithm' => $algorithm,
'password' => $password
])
@ -369,7 +380,7 @@ class AccountApiTest extends TestCase
// Set new password without old one
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/password', [
->json($this->method, $this->route.'/me/password', [
'algorithm' => $newAlgorithm,
'password' => $newPassword
])
@ -380,7 +391,7 @@ class AccountApiTest extends TestCase
// Set the new password with incorrect old password
$response = $this->keyAuthenticated($account)
->json($this->method, $this->route.'/password', [
->json($this->method, $this->route.'/me/password', [
'algorithm' => $newAlgorithm,
'old_password' => 'blabla',
'password' => $newPassword
@ -392,7 +403,7 @@ class AccountApiTest extends TestCase
// Set the new password
$this->keyAuthenticated($account)
->json($this->method, $this->route.'/password', [
->json($this->method, $this->route.'/me/password', [
'algorithm' => $newAlgorithm,
'old_password' => $password,
'password' => $newPassword

View file

@ -8,7 +8,7 @@
#%define _datadir %{_datarootdir}
#%define _docdir %{_datadir}/doc
%define build_number 41
%define build_number 42
%define var_dir /var/opt/belledonne-communications
%define opt_dir /opt/belledonne-communications/share/flexisip-account-manager
%define env_file "$RPM_BUILD_ROOT/etc/flexisip-account-manager/flexiapi.env"